<!DOCTYPE html>
<html lang="zh-CN">
<head hexo-theme='https://github.com/volantis-x/hexo-theme-volantis/tree/4.1.5'>
  <meta charset="utf-8">
  <!-- SEO相关 -->
  
    
  
  <!-- 渲染优化 -->
  <meta http-equiv='x-dns-prefetch-control' content='on' />
  <link rel='dns-prefetch' href='https://cdn.jsdelivr.net'>
  <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
  <meta name="renderer" content="webkit">
  <meta name="force-rendering" content="webkit">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
  <meta name="HandheldFriendly" content="True" >
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  <!-- 页面元数据 -->
  
  <title>Rust - Learn - Schenk - Blog</title>
  
    <meta name="keywords" content="rust">
  

  
    <meta name="description" content="Rust基础学习笔记">
  

  <!-- feed -->
  

  <!-- import meta -->
  

  <!-- link -->
  
    <link rel="shortcut icon" type='image/x-icon' href="https://cdn.jsdelivr.net/gh/Schenk75/Source/logos/steroids.svg">
  

  <!-- import link -->
  

  
    
<link rel="stylesheet" href="/css/first.css">

  

  
  <link rel="stylesheet" href="/css/style.css" media="print" onload="this.media='all';this.onload=null">
  <noscript><link rel="stylesheet" href="/css/style.css"></noscript>
  

  <script id="loadcss"></script>

</head>

<body>
  

<header id="l_header" class="l_header auto shadow blur floatable show" style='opacity: 0' >
  <div class='container'>
  <div id='wrapper'>
    <div class='nav-sub'>
      <p class="title"></p>
      <ul class='switcher nav-list-h m-phone' id="pjax-header-nav-list">
        <li><a id="s-comment" class="fas fa-comments fa-fw" target="_self" href='javascript:void(0)'></a></li>
        
          <li><a id="s-toc" class="s-toc fas fa-list fa-fw" target="_self" href='javascript:void(0)'></a></li>
        
      </ul>
    </div>
		<div class="nav-main">
      
        
        <a class="title flat-box" target="_self" href='/'>
          
            <img no-lazy class='logo' src='https://cdn.jsdelivr.net/gh/Schenk75/Source@latest/logos/taiga.svg'/>
          
          
          
        </a>
      

			<div class='menu navigation'>
				<ul class='nav-list-h m-pc'>
          
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/
                  
                  
                  
                    id="home"
                  >
                  <i class='fab fa-stack-overflow fa-fw'></i>主页
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/
                  
                  
                  
                    id="categories"
                  >
                  <i class='fas fa-folder-open fa-fw'></i>分类
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/tags/
                  
                  
                  
                    id="tags"
                  >
                  <i class='fas fa-tags fa-fw'></i>标签
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/archives/
                  
                  
                  
                    id="archives"
                  >
                  <i class='fas fa-archive fa-fw'></i>归档
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/friends/
                  
                  
                  
                    id="friends"
                  >
                  <i class='fas fa-link fa-fw'></i>友链
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/about/
                  
                  
                  
                    id="about"
                  >
                  <i class='fas fa-info-circle fa-fw'></i>关于
                </a>
                
              </li>
            
          
          
				</ul>
			</div>

      <div class="m_search">
        <form name="searchform" class="form u-search-form">
          <i class="icon fas fa-search fa-fw"></i>
          <input type="text" class="input u-search-input" placeholder="Search..." />
        </form>
      </div>

			<ul class='switcher nav-list-h m-phone'>
				
					<li><a class="s-search fas fa-search fa-fw" target="_self" href='javascript:void(0)'></a></li>
				
				<li>
          <a class="s-menu fas fa-bars fa-fw" target="_self" href='javascript:void(0)'></a>
          <ul class="menu-phone list-v navigation white-box">
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/
                  
                  
                  
                    id="home"
                  >
                  <i class='fab fa-stack-overflow fa-fw'></i>主页
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/
                  
                  
                  
                    id="categories"
                  >
                  <i class='fas fa-folder-open fa-fw'></i>分类
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/tags/
                  
                  
                  
                    id="tags"
                  >
                  <i class='fas fa-tags fa-fw'></i>标签
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/archives/
                  
                  
                  
                    id="archives"
                  >
                  <i class='fas fa-archive fa-fw'></i>归档
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/friends/
                  
                  
                  
                    id="friends"
                  >
                  <i class='fas fa-link fa-fw'></i>友链
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/about/
                  
                  
                  
                    id="about"
                  >
                  <i class='fas fa-info-circle fa-fw'></i>关于
                </a>
                
              </li>
            
          
            
          </ul>
        </li>
			</ul>
		</div>
	</div>
  </div>
</header>

  <div id="l_body">
    <div id="l_cover">
  
    
        <div id="full" class='cover-wrapper post dock' style="display: none;">
          
            <div class='cover-bg lazyload placeholder' data-bg="https://cdn.jsdelivr.net/gh/Schenk75/Source@master/common/interstellar.jpg"></div>
          
          <div class='cover-body'>
  <div class='top'>
    
    
      <p class="title">Schenk - Blog</p>
    
    
      <p class="subtitle">SJTUer | Cuber</p>
    
  </div>
  <div class='bottom'>
    <div class='menu navigation'>
      <div class='list-h'>
        
          
            <a href="/categories/"
              
              
              id="categories">
              <i class='fas fa-folder-open fa-fw'></i><p>分类</p>
            </a>
          
            <a href="/tags/"
              
              
              id="tags">
              <i class='fas fa-tags fa-fw'></i><p>标签</p>
            </a>
          
            <a href="/archives/"
              
              
              id="archives">
              <i class='fas fa-archive fa-fw'></i><p>归档</p>
            </a>
          
            <a href="/friends/"
              
              
              id="friends">
              <i class='fas fa-link fa-fw'></i><p>友链</p>
            </a>
          
            <a href="/about/"
              
              
              id="about">
              <i class='fas fa-info-circle fa-fw'></i><p>关于</p>
            </a>
          
        
      </div>
    </div>
  </div>
</div>

          <div id="scroll-down" style="display: none;"><i class="fa fa-chevron-down scroll-down-effects"></i></div>
        </div>
    
  
  </div>

    <div id='safearea'>
      <div class='body-wrapper' id="pjax-container">
        

<div class='l_main'>
  <article class="article post white-box reveal md shadow floatable article-type-post" id="post" itemscope itemprop="blogPost">
  


  
  <div class="article-meta" id="top">
    
    
    
      <h1 class="title">
        Rust - Learn
      </h1>
      <div class='new-meta-box'>
        
          
            
<div class='new-meta-item author'>
  <a class='author' href="/" rel="nofollow">
    <img no-lazy src="https://cdn.jsdelivr.net/gh/Schenk75/Source@master/common/avatar.jpg">
    <p>Schenk</p>
  </a>
</div>

          
        
          
            
  <div class='new-meta-item category'>
    <a class='notlink'>
      <i class="fas fa-folder-open fa-fw" aria-hidden="true"></i>
      <a class="category-link" href="/categories/Notes/">Notes</a><span class="sep"></span><a class="category-link" href="/categories/Rust/">Rust</a>
    </a>
  </div>


          
        
          
            <div class="new-meta-item date" itemprop="dateUpdated" datetime="2022-04-28T15:34:00+08:00">
  <a class='notlink'>
    <i class="fas fa-edit fa-fw" aria-hidden="true"></i>
    <p>更新于：2022年4月28日</p>
  </a>
</div>

          
        
          
            
  <div class="new-meta-item wordcount">
    <a class='notlink'>
      <i class="fas fa-keyboard fa-fw" aria-hidden="true"></i>
      <p>字数：16.9k字</p>
    </a>
  </div>
  <div class="new-meta-item readtime">
    <a class='notlink'>
      <i class="fas fa-hourglass-half fa-fw" aria-hidden="true"></i>
      <p>时长：72分钟</p>
    </a>
  </div>


          
        
          
            
  <div class="new-meta-item browse leancloud">
    <a class='notlink'>
      
      <div id="lc-pv" data-title="Rust - Learn" data-path="/2020/11/16/learning-notes/Rust-notes/">
        <i class="fas fa-eye fa-fw" aria-hidden="true"></i>
        <span id='number'><i class="fas fa-circle-notch fa-spin fa-fw" aria-hidden="true"></i></span>
        次浏览
      </div>
    </a>
  </div>


          
        
      </div>
    
  </div>


  
  <h2 id="Ch0-安装Rust">Ch0 安装Rust</h2>
<ul>
<li>
<p>使用rustup安装</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl --proto <span class="string">&#x27;=https&#x27;</span> --tlsv1.2 -sSf https://sh.rustup.rs | sh</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>安装时出现的问题（<s>未完全</s>解决）：默认<code>.cargo</code>环境变量设置为了<code>/home/&lt;username&gt;/~/.cargo</code>，导致在用户家目录下又新建了<code>~</code>目录，在安装完rust后，将<code>.cargo</code>目录移动到<code>~/</code>家目录下，并修改所有可能会更改环境变量的文件，包括<code>~/.profile</code>、<code>/etc/profile</code>、<code>/etc/bash.bashrc</code>、<code>~/.cargo/env</code>，将其中的<code>/home/&lt;username&gt;/~/.cargo</code>改为<code>~/.cargo</code>。但是每当打开终端时，环境变量PATH还是会自动添加<code>/home/&lt;username&gt;/~/.cargo/bin</code></p>
<ul>
<li>
<p><s>暂时的</s>解决方案：在<code>~/.bashrc</code>文件中添加语句，覆盖错误的环境变量(重启后就成功了)</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> PATH=~/.cargo/bin:<span class="variable">$PATH</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
</ul>
<h2 id="Ch1-Cargo">Ch1 Cargo</h2>
<h3 id="1-1-使用Cargo创建项目">1.1 使用Cargo创建项目</h3>
<ul>
<li>
<p>创建hello_world目录，并在其中新建二进制项目hello_world</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo new hello_world</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>创建库项目</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo new hello_world --lib</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="1-1-1-Cargo-toml">1.1.1 Cargo.toml</h4>
<p>Cargo.toml是项目的配置文件，通过cargo new自动生成</p>
<figure class="highlight toml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[package]</span></span><br><span class="line"><span class="attr">name</span> = <span class="string">&quot;hello_world&quot;</span></span><br><span class="line"><span class="attr">version</span> = <span class="string">&quot;0.1.0&quot;</span></span><br><span class="line"><span class="attr">authors</span> = [<span class="string">&quot;Your Name &lt;you@example.com&gt;&quot;</span>]</span><br><span class="line"><span class="attr">edition</span> = <span class="string">&quot;2018&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="section">[dependencies]</span></span><br></pre></td></tr></table></figure>
<ul>
<li>[package]片段：配置一个包，包含项目名称、版本、作者和Rust版本</li>
<li>[dependencies]片段：罗列项目依赖</li>
</ul>
<h4 id="1-1-2-源代码目录src">1.1.2 源代码目录src</h4>
<p>包含main.rs以及其他源文件</p>
<h3 id="1-2-构建并运行Cargo项目">1.2 构建并运行Cargo项目</h3>
<p><strong>编译项目</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo build</span><br></pre></td></tr></table></figure>
<p><strong>编译并运行项目</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo run</span><br></pre></td></tr></table></figure>
<p><strong>快速检查代码确保其可以编译，但不生成可执行文件</strong></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo check</span><br></pre></td></tr></table></figure>
<p>以上命令会生成以下文件：</p>
<h4 id="1-2-1-可执行文件">1.2.1 可执行文件</h4>
<p>存放目录为<code>./target/debug/hello_world</code></p>
<h4 id="1-2-2-Cargo-lock">1.2.2 Cargo.lock</h4>
<p>Cargo.lock记录项目依赖的实际版本，确保项目构建是可重现的，这个文件不需要人为修改</p>
<h3 id="1-3-发布-release-构建">1.3 发布(release)构建</h3>
<p>当项目最终准备好发布时，可以优化编译项目是的Rust代码运行更快</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo build --release</span><br></pre></td></tr></table></figure>
<p>此时生成的可执行文件在<code>./target/release/</code>目录下</p>
<h2 id="Ch2-引入-guess-number">Ch2 引入 - guess_number</h2>
<h3 id="2-1-创建变量">2.1 创建变量</h3>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> guess = <span class="built_in">String</span>::new();</span><br></pre></td></tr></table></figure>
<ul>
<li><code>let</code> 创建变量，变量默认不可变</li>
<li><code>mut</code> 使得变量可变</li>
<li><code>::</code> 表明new是<code>String</code>类型的一个关联函数</li>
</ul>
<h3 id="2-2-从标准输入读取">2.2 从标准输入读取</h3>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::io;</span><br><span class="line"></span><br><span class="line">io::stdin().read_line(&amp;<span class="keyword">mut</span> guess).expect(<span class="string">&quot;Failed to read line&quot;</span>);</span><br></pre></td></tr></table></figure>
<ul>
<li><code>io::stdin</code>函数返回一个终端标准输入句柄</li>
<li><code>read_line</code>将标准输入存入字符串</li>
<li><code>&amp;</code>表示这个参数是一个引用</li>
<li><code>read_line</code>函数返回一个<code>Result</code>类型（枚举），成员有<code>Ok</code>和<code>Err</code></li>
<li><code>Result</code>实例有<code>expect</code>方法：
<ul>
<li>若<code>Result</code>值为<code>Ok</code>，<code>expect</code>获取<code>Ok</code>中的值并原样返回</li>
<li>若<code>Result</code>值为<code>Err</code>，<code>expect</code>导致程序崩溃，并显式当做参数传给<code>expect</code>的信息</li>
</ul>
</li>
</ul>
<h3 id="2-3-crate">2.3 crate</h3>
<p>crate是一个Rust代码包</p>
<ul>
<li>我们构建的项目是一个<strong>二进制crate</strong></li>
<li>rand crate是一个<strong>库crate</strong></li>
</ul>
<h4 id="2-3-1-导入外部crate">2.3.1 导入外部crate</h4>
<p>以rand crate为例</p>
<ul>
<li>
<p>在使用rand编写代码之前需要修改<code>Cargo.toml</code>文件</p>
<figure class="highlight toml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[dependencies]</span></span><br><span class="line"></span><br><span class="line"><span class="attr">rand</span> = <span class="string">&quot;0.5.5&quot;</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p>再进行<code>cargo build</code>，此时会从Crates.io拷贝数据并下载对应的库文件，需要更换国内镜像源进行加速，编辑<code>.cargo/config</code>文件，加入以下内容</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[source.crates-io]</span><br><span class="line">registry &#x3D; &quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;crates.io-index&quot;</span><br><span class="line">replace-with &#x3D; &#39;ustc&#39;</span><br><span class="line">[source.ustc]</span><br><span class="line">registry &#x3D; &quot;git:&#x2F;&#x2F;mirrors.ustc.edu.cn&#x2F;crates.io-index&quot;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="2-3-2-更新crate">2.3.2 更新crate</h4>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo update</span><br></pre></td></tr></table></figure>
<h4 id="2-3-3-获取所有本地依赖提供的文档">2.3.3 获取所有本地依赖提供的文档</h4>
<p>查看应该 <code>use</code>哪个<code>trait</code>以及该从<code>crate</code>中调用哪个方法</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo doc --open</span><br></pre></td></tr></table></figure>
<h2 id="Ch3-常见编程概念">Ch3 常见编程概念</h2>
<h3 id="3-1-变量和可变性">3.1 变量和可变性</h3>
<ul>
<li>
<p>使用<code>let</code>声明的变量默认是不可改变的</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> x = <span class="number">3</span>;</span><br><span class="line">x = <span class="number">5</span>;   <span class="comment">// 非法</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p>在变量名之前加<code>mut</code>来使其可变</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> x = <span class="number">3</span>;</span><br><span class="line">x = <span class="number">5</span>;   <span class="comment">// 合法</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="3-1-1-变量和常量的区别">3.1.1 变量和常量的区别</h4>
<ul>
<li>
<p>常量使用关键字<code>const</code>声明，并且必须<strong>注明值的类型</strong></p>
</li>
<li>
<p>不能对常量使用<code>mut</code></p>
</li>
<li>
<p>常量只能被设置为常量表达式，而不能是函数调用的结果</p>
</li>
</ul>
<h4 id="3-1-2-隐藏">3.1.2 隐藏</h4>
<ul>
<li>
<p>定义一个与之前变量同名的新变量，而新变量会<strong>隐藏</strong>之前的变量</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> x = <span class="number">5</span>;</span><br><span class="line"><span class="keyword">let</span> x = x + <span class="number">1</span>;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>当再次使用<code>let</code>时，实际上创建了一个新变量，我们可以改变值的类型，但复用这个名字</p>
</li>
</ul>
<h3 id="3-2-数据类型">3.2 数据类型</h3>
<p>Rust 是 <strong>静态类型</strong>语言，在编译时就必须知道所有变量的类型</p>
<h4 id="3-2-1-标量类型">3.2.1 标量类型</h4>
<ul>
<li><strong>标量</strong>类型代表一个单独的值</li>
</ul>
<h5 id="整型">整型</h5>
<table>
<thead>
<tr>
<th>长度</th>
<th>有符号</th>
<th>无符号</th>
</tr>
</thead>
<tbody>
<tr>
<td>8-bit</td>
<td><code>i8</code></td>
<td><code>u8</code></td>
</tr>
<tr>
<td>16-bit</td>
<td><code>i16</code></td>
<td><code>u16</code></td>
</tr>
<tr>
<td>32-bit</td>
<td><code>i32</code></td>
<td><code>u32</code></td>
</tr>
<tr>
<td>64-bit</td>
<td><code>i64</code></td>
<td><code>u64</code></td>
</tr>
<tr>
<td>128-bit</td>
<td><code>i128</code></td>
<td><code>u128</code></td>
</tr>
<tr>
<td>arch</td>
<td><code>isize</code></td>
<td><code>usize</code></td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>数字字面值</th>
<th>例子</th>
</tr>
</thead>
<tbody>
<tr>
<td>Decimal</td>
<td><code>98_222</code></td>
</tr>
<tr>
<td>Hex</td>
<td><code>0xff</code></td>
</tr>
<tr>
<td>Octal</td>
<td><code>0o77</code></td>
</tr>
<tr>
<td>Binary</td>
<td><code>0b1111_0000</code></td>
</tr>
<tr>
<td>Byte (<code>u8</code> only)</td>
<td><code>b'A'</code></td>
</tr>
</tbody>
</table>
<h5 id="浮点型">浮点型</h5>
<ul>
<li>
<p>Rust 的浮点数类型是 <code>f32</code> 和 <code>f64</code>，分别占 32 位和 64 位</p>
</li>
<li>
<p>默认类型是 <code>f64</code></p>
</li>
</ul>
<h5 id="布尔型">布尔型</h5>
<ul>
<li><code>bool</code>，两个可能的值<code>true</code>和<code>false</code></li>
</ul>
<h5 id="字符类型">字符类型</h5>
<ul>
<li><code>char</code> 类型的大小为四个字节，并代表了一个 Unicode 标量值</li>
</ul>
<h4 id="3-2-2-复合类型">3.2.2 复合类型</h4>
<h5 id="元组类型">元组类型</h5>
<ul>
<li>
<p>元组长度固定：一旦声明，其长度不会增大或缩小</p>
</li>
<li>
<p>元组中的每一个位置都有一个类型，而且这些不同值的类型也不必是相同的</p>
</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> tup: (<span class="built_in">i32</span>, <span class="built_in">f64</span>, <span class="built_in">u8</span>) = (<span class="number">500</span>, <span class="number">6.4</span>, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> (x, y, z) = tup;   <span class="comment">// 解构</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> five_hundred = tup.<span class="number">0</span>;   <span class="comment">// 使用索引访问</span></span><br></pre></td></tr></table></figure>
<h5 id="数组类型">数组类型</h5>
<ul>
<li>数组中的每个元素的类型必须相同</li>
<li>Rust 中的数组是固定长度的：一旦声明，它们的长度不能增长或缩小</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a: [<span class="built_in">i32</span>; <span class="number">5</span>] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> b = [<span class="number">0</span>; <span class="number">10</span>];   <span class="comment">// 初始化一个长度为10的全零数组</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> first = a[<span class="number">0</span>];   <span class="comment">// 使用索引访问</span></span><br></pre></td></tr></table></figure>
<h3 id="3-3-函数">3.3 函数</h3>
<ul>
<li>
<p><code>fn</code> 关键字声明新函数</p>
</li>
<li>
<p>在函数签名中，<strong>必须</strong>声明每个参数的类型</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">another_function</span></span>(x: <span class="built_in">i32</span>, y: <span class="built_in">i32</span>) &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;The value of x is: &#123;&#125;&quot;</span>, x);</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;The value of y is: &#123;&#125;&quot;</span>, y);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="3-3-1-具有返回值的函数">3.3.1 具有返回值的函数</h4>
<ul>
<li>
<p>以表达式结尾</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">plus_one</span></span>(x: <span class="built_in">i32</span>) -&gt; <span class="built_in">i32</span> &#123;</span><br><span class="line">    x + <span class="number">1</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="3-4-注释">3.4 注释</h3>
<ul>
<li>// 单行注释</li>
</ul>
<h3 id="3-5-控制流">3.5 控制流</h3>
<h4 id="3-5-1-if表达式">3.5.1 if表达式</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> number % <span class="number">4</span> == <span class="number">0</span> &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;number is divisible by 4&quot;</span>);</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> number % <span class="number">3</span> == <span class="number">0</span> &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;number is divisible by 3&quot;</span>);</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> number % <span class="number">2</span> == <span class="number">0</span> &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;number is divisible by 2&quot;</span>);</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;number is not divisible by 4, 3, or 2&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>Rust 不会尝试自动地将非布尔值转换为布尔值，所以<code>if</code>后跟的表达式必须是<code>bool</code></li>
</ul>
<h5 id="在let语句中使用if">在let语句中使用if</h5>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> number = <span class="keyword">if</span> condition &#123;</span><br><span class="line">    <span class="number">5</span></span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="number">6</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<ul>
<li>代码块的值是其最后一个表达式的值</li>
<li><code>if</code>和<code>else</code>中返回的类型要相同</li>
</ul>
<h4 id="3-5-2-循环">3.5.2 循环</h4>
<h5 id="loop">loop</h5>
<ul>
<li>
<p>无限循环，直到按下ctrl+c，或有break</p>
</li>
<li>
<p>内循环可以 <code>continue</code> 或者 <code>break</code> 外循环，此时需要在外循环添加生命周期：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#![allow(unreachable_code)]</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="symbol">&#x27;outer</span>: <span class="keyword">loop</span> &#123;</span><br><span class="line">        <span class="built_in">println!</span>(<span class="string">&quot;Entered the outer loop&quot;</span>);</span><br><span class="line">        <span class="symbol">&#x27;inner</span>: <span class="keyword">loop</span> &#123;</span><br><span class="line">            <span class="built_in">println!</span>(<span class="string">&quot;Entered the inner loop&quot;</span>);</span><br><span class="line">            <span class="comment">// This would break only the inner loop</span></span><br><span class="line">            <span class="comment">//break;</span></span><br><span class="line">            <span class="comment">// This breaks the outer loop</span></span><br><span class="line">            <span class="keyword">break</span> <span class="symbol">&#x27;outer</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p><code>loop</code> 可以返回值，返回 <code>break</code> 后的表达式</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> <span class="keyword">mut</span> counter = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">let</span> result = <span class="keyword">loop</span> &#123;</span><br><span class="line">        counter += <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">if</span> counter == <span class="number">10</span> &#123;</span><br><span class="line">            <span class="keyword">break</span> counter * <span class="number">2</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="built_in">assert_eq!</span>(result, <span class="number">20</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h5 id="while">while</h5>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> number = <span class="number">3</span>;</span><br><span class="line"><span class="keyword">while</span> number != <span class="number">0</span> &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;&#123;&#125;!&quot;</span>, number);</span><br><span class="line">    number = number - <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="for遍历集合">for遍历集合</h5>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = [<span class="number">10</span>, <span class="number">20</span>, <span class="number">30</span>, <span class="number">40</span>, <span class="number">50</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">// iter引用集合a，在循环结束后仍然可以使用a</span></span><br><span class="line"><span class="keyword">for</span> element <span class="keyword">in</span> a.iter() &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;the value is: &#123;&#125;&quot;</span>, element);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// into_iter移动集合a的所有权，在循环结束后不能使用a</span></span><br><span class="line"><span class="keyword">for</span> element <span class="keyword">in</span> a.into_iter() &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;the value is: &#123;&#125;&quot;</span>, element);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> b = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">// iter_mut引用可变集合b，可以在循环中改变b中的元素</span></span><br><span class="line"><span class="keyword">for</span> element <span class="keyword">in</span> b.iter_mut() &#123;</span><br><span class="line">    *element += <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Ch4-所有权">Ch4 所有权</h2>
<h3 id="4-1-什么是所有权">4.1 什么是所有权</h3>
<ul>
<li>Rust管理内存的方式：通过所有权系统管理内存，编译器在编译时会根据一系列的规则进行检查</li>
</ul>
<h4 id="4-1-1-所有权规则：">4.1.1 所有权规则：</h4>
<blockquote>
<ol>
<li>Rust 中的每一个值都有一个被称为其 <strong>所有者</strong>（<em>owner</em>）的变量。</li>
<li>值有且只有一个所有者。</li>
<li>当所有者（变量）离开作用域，这个值将被丢弃。</li>
</ol>
</blockquote>
<h4 id="4-1-2-变量作用域">4.1.2 变量作用域</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&#123;                      <span class="comment">// s 在这里无效, 它尚未声明</span></span><br><span class="line">    <span class="keyword">let</span> s = <span class="string">&quot;hello&quot;</span>;   <span class="comment">// 从此处起，s 是有效的</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 使用 s</span></span><br><span class="line">&#125;                      <span class="comment">// 此作用域已结束，s 不再有效</span></span><br></pre></td></tr></table></figure>
<h4 id="4-1-3-String类型">4.1.3 String类型</h4>
<ul>
<li>字符串的字面值是不可变的，而<code>String</code>类型的字符串是可变的</li>
<li><code>String</code>类型的字符串被分配到<strong>堆</strong>上，所以能够存储在编译时未知大小的文本</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 基于字符串字面值来创建String</span></span><br><span class="line"><span class="keyword">let</span> s = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>);</span><br></pre></td></tr></table></figure>
<h4 id="4-1-4-内存与分配">4.1.4 内存与分配</h4>
<p>对于<code>String</code>类型，为了支持一个可变，可增长的文本片段，需要在堆上分配一块在编译时未知大小的内存来存放内容。这意味着：</p>
<ul>
<li>必须在运行时向操作系统请求内存</li>
<li>需要一个当我们处理完<code>String</code>时将内存返回给操作系统的方法</li>
</ul>
<p>Rust处理第二点的策略：内存在拥有它的变量离开作用域后就被自动释放</p>
<h4 id="4-1-5-存储在堆上的变量">4.1.5 存储在堆上的变量</h4>
<h5 id="1-移动">1. 移动</h5>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> s1 = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line"><span class="keyword">let</span> s2 = s1;</span><br></pre></td></tr></table></figure>
<p><img src="https://cdn.jsdelivr.net/gh/Schenk75/Source@master/notes/Rust-notes/image-20201110234252508.png" class="lazyload" data-srcset="https://cdn.jsdelivr.net/gh/Schenk75/Source@master/notes/Rust-notes/image-20201110234252508.png" srcset="" alt="image-20201110234252508"></p>
<p><code>String</code> 由三部分组成，如上图所示：一个指向存放字符串内容内存的指针，一个长度，和一个容量。</p>
<p>当 <code>s2</code> 和 <code>s1</code> 离开作用域，他们都会尝试释放相同的内存。这是一个叫做<strong>二次释放</strong>的错误，两次释放（相同）内存会导致内存污染，它可能会导致潜在的安全漏洞。</p>
<p>在Rust中，经过以上语句，会认为s1不再有效，即<code>s1</code> 被<strong>移动</strong>到了 <code>s2</code> 中，因此当<code>s1</code>离开作用域时不会释放内存。</p>
<h5 id="克隆">克隆</h5>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> s1 = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line"><span class="keyword">let</span> s2 = s1.clone();</span><br></pre></td></tr></table></figure>
<p><code>s2</code>深度复制了<code>s1</code>堆上的内容，而不仅仅是栈上的指针。</p>
<ul>
<li>以上只针对存储在堆上的类型，而对于类似整型等存储在栈上的类型，可以直接拷贝，变量值不会被移动</li>
</ul>
<h4 id="4-1-6-所有权与函数">4.1.6 所有权与函数</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> s1 = gives_ownership();         <span class="comment">// gives_ownership 将返回值移给 s1</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> s2 = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>);     <span class="comment">// s2 进入作用域</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> s3 = takes_and_gives_back(s2);  <span class="comment">// s2 被移动到</span></span><br><span class="line">                                        <span class="comment">// takes_and_gives_back 中, </span></span><br><span class="line">                                        <span class="comment">// 它也将返回值移给 s3</span></span><br><span class="line">&#125; <span class="comment">// 这里, s3 移出作用域并被丢弃。s2 也移出作用域，但已被移走，</span></span><br><span class="line">  <span class="comment">// 所以什么也不会发生。s1 移出作用域并被丢弃</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">gives_ownership</span></span>() -&gt; <span class="built_in">String</span> &#123;             <span class="comment">// gives_ownership 将返回值移动给</span></span><br><span class="line">                                             <span class="comment">// 调用它的函数</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> some_string = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>); <span class="comment">// some_string 进入作用域.</span></span><br><span class="line"></span><br><span class="line">    some_string                              <span class="comment">// 返回 some_string 并移出给调用的函数</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// takes_and_gives_back 将传入字符串并返回该值</span></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">takes_and_gives_back</span></span>(a_string: <span class="built_in">String</span>) -&gt; <span class="built_in">String</span> &#123; <span class="comment">// a_string 进入作用域</span></span><br><span class="line"></span><br><span class="line">    a_string  <span class="comment">// 返回 a_string 并移出给调用的函数</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="4-2-引用与借用">4.2 引用与借用</h3>
<p>当<code>String</code>类型的变量传入函数中时，如何以引用的方式传入而不是将所有权交给函数？</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> s1 = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">    <span class="keyword">let</span> len = calculate_length(&amp;s1);</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;The length of &#x27;&#123;&#125;&#x27; is &#123;&#125;.&quot;</span>, s1, len);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">calculate_length</span></span>(s: &amp;<span class="built_in">String</span>) -&gt; <span class="built_in">usize</span> &#123;</span><br><span class="line">    s.len()</span><br><span class="line">&#125;  <span class="comment">// 这里，s 离开了作用域。但因为它并不拥有引用值的所有权，</span></span><br><span class="line">   <span class="comment">// 所以什么也不会发生</span></span><br></pre></td></tr></table></figure>
<p><img src="https://cdn.jsdelivr.net/gh/Schenk75/Source@master/notes/Rust-notes/image-20201110234314662.png" class="lazyload" data-srcset="https://cdn.jsdelivr.net/gh/Schenk75/Source@master/notes/Rust-notes/image-20201110234314662.png" srcset="" alt="image-20201110234314662"></p>
<ul>
<li>
<p><code>&amp;s1</code>语法让我们创建一个<strong>指向</strong>值<code>s1</code>的引用，但是并不拥有它</p>
</li>
<li>
<p>我们将获取引用作为函数参数称为<strong>借用</strong></p>
</li>
<li>
<p>引用<strong>默认</strong>不允许被修改</p>
</li>
</ul>
<h4 id="4-2-1-可变引用">4.2.1 可变引用</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> <span class="keyword">mut</span> s = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">    change(&amp;<span class="keyword">mut</span> s);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">change</span></span>(some_string: &amp;<span class="keyword">mut</span> <span class="built_in">String</span>) &#123;</span><br><span class="line">    some_string.push_str(<span class="string">&quot;, world&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>
<p>可变引用有一个很大的限制：在特定作用域中的特定数据有且只有一个可变引用，如以下代码是非法的：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> s = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// s被引用了两次，非法</span></span><br><span class="line"><span class="keyword">let</span> r1 = &amp;<span class="keyword">mut</span> s;</span><br><span class="line"><span class="keyword">let</span> r2 = &amp;<span class="keyword">mut</span> s;</span><br></pre></td></tr></table></figure>
<ul>
<li>
<p>这样的限制可以避免<strong>数据竞争</strong>，即</p>
<ul>
<li>两个或更多指针同时访问同一数据</li>
<li>至少有一个指针被用来写入数据。</li>
<li>没有同步数据访问的机制</li>
</ul>
</li>
<li>
<p>可以使用大括号来创建一个新的作用域，以允许拥有多个可变引用，只是不能<strong>同时</strong>拥有</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> s = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">let</span> r1 = &amp;<span class="keyword">mut</span> s;</span><br><span class="line">&#125; <span class="comment">// r1 在这里离开了作用域，所以我们完全可以创建一个新的引用</span></span><br><span class="line"><span class="keyword">let</span> r2 = &amp;<span class="keyword">mut</span> s;</span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
<li>
<p>可变引用和不可变引用不能同时存在，如以下代码非法：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> s = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> r1 = &amp;s; <span class="comment">// 没问题</span></span><br><span class="line"><span class="keyword">let</span> r2 = &amp;s; <span class="comment">// 没问题</span></span><br><span class="line"><span class="keyword">let</span> r3 = &amp;<span class="keyword">mut</span> s; <span class="comment">// 大问题</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">println!</span>(<span class="string">&quot;&#123;&#125;, &#123;&#125;, and &#123;&#125;&quot;</span>, r1, r2, r3);</span><br></pre></td></tr></table></figure>
<ul>
<li>
<p>由于一个引用的作用域从声明的地方开始一直持续到最后一次使用为止，所以以下代码合法：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> s = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> r1 = &amp;s; <span class="comment">// 没问题</span></span><br><span class="line"><span class="keyword">let</span> r2 = &amp;s; <span class="comment">// 没问题</span></span><br><span class="line"><span class="built_in">println!</span>(<span class="string">&quot;&#123;&#125; and &#123;&#125;&quot;</span>, r1, r2);</span><br><span class="line"><span class="comment">// 此位置之后 r1 和 r2 不再使用</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> r3 = &amp;<span class="keyword">mut</span> s; <span class="comment">// 没问题</span></span><br><span class="line"><span class="built_in">println!</span>(<span class="string">&quot;&#123;&#125;&quot;</span>, r3);</span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
</ul>
<h4 id="4-2-2-悬垂引用">4.2.2 悬垂引用</h4>
<ul>
<li>
<p>所谓<strong>悬垂指针</strong>是其指向的内存可能已经被分配给其它持有者</p>
</li>
<li>
<p>在Rust中编译器确保引用永远也不会变成悬垂状态：当你拥有一些数据的引用，编译器确保数据不会在其引用之前离开作用域，如以下函数非法：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">dangle</span></span>() -&gt; &amp;<span class="built_in">String</span> &#123; <span class="comment">// dangle 返回一个字符串的引用</span></span><br><span class="line">    <span class="keyword">let</span> s = <span class="built_in">String</span>::from(<span class="string">&quot;hello&quot;</span>); <span class="comment">// s 是一个新字符串</span></span><br><span class="line">    &amp;s <span class="comment">// 返回字符串 s 的引用</span></span><br><span class="line">&#125; <span class="comment">// 这里 s 离开作用域并被丢弃。其内存被释放。危险！</span></span><br></pre></td></tr></table></figure>
<ul>
<li>而应该直接返回<code>String</code>，将所有权移动出去</li>
</ul>
</li>
</ul>
<h3 id="4-3-Slice类型">4.3 Slice类型</h3>
<ul>
<li><code>slice</code>是一个没有所有权的数据类型</li>
<li><code>slice</code>允许你引用集合中一段连续的元素序列，而不用引用整个集合</li>
</ul>
<h4 id="4-3-1-字符串slice">4.3.1 字符串slice</h4>
<p>字符串 slice是<code>String</code>中一部分值的引用</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="built_in">String</span>::from(<span class="string">&quot;hello world&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> hello = &amp;s[<span class="number">0</span>..<span class="number">5</span>];</span><br><span class="line"><span class="keyword">let</span> world = &amp;s[<span class="number">6</span>..<span class="number">11</span>];</span><br><span class="line"><span class="keyword">let</span> all_s = &amp;s[..];</span><br></pre></td></tr></table></figure>
<ul>
<li>字符串字面值就是slice，如<code>let s = &quot;Hello world&quot;</code>中，<code>s</code>的类型是<code>&amp;str</code>，是一个指向二进制程序特定位置的slice</li>
</ul>
<h4 id="4-3-2-其他类型的slice">4.3.2 其他类型的slice</h4>
<p>如数组slice:</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> slice = &amp;a[<span class="number">1</span>..<span class="number">3</span>];</span><br></pre></td></tr></table></figure>
<h2 id="Ch5-结构体">Ch5 结构体</h2>
<h3 id="5-1-结构体的定义和实例化">5.1 结构体的定义和实例化</h3>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">User</span></span> &#123;</span><br><span class="line">    username: <span class="built_in">String</span>,</span><br><span class="line">    email: <span class="built_in">String</span>,</span><br><span class="line">    sign_in_count: <span class="built_in">u64</span>,</span><br><span class="line">    active: <span class="built_in">bool</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 实例化</span></span><br><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> user1 = User &#123;</span><br><span class="line">    email: <span class="built_in">String</span>::from(<span class="string">&quot;someone@example.com&quot;</span>),</span><br><span class="line">    username: <span class="built_in">String</span>::from(<span class="string">&quot;someusername123&quot;</span>),</span><br><span class="line">    active: <span class="literal">true</span>,</span><br><span class="line">    sign_in_count: <span class="number">1</span>,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取并修改字段</span></span><br><span class="line">user1.email = <span class="built_in">String</span>::from(<span class="string">&quot;anotheremail@example.com&quot;</span>);</span><br></pre></td></tr></table></figure>
<ul>
<li>想要修改实例中的字段，必须将整个结构体声明为可变</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> user2 = User &#123;</span><br><span class="line">    email: <span class="built_in">String</span>::from(<span class="string">&quot;another@example.com&quot;</span>),</span><br><span class="line">    username: <span class="built_in">String</span>::from(<span class="string">&quot;anotherusername567&quot;</span>),</span><br><span class="line">    ..user1</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<ul>
<li><code>..</code>语法指定了剩余未显式设置值的字段应有与给定实例对应字段相同的值</li>
</ul>
<h4 id="5-1-1-元组结构体">5.1.1 元组结构体</h4>
<ul>
<li>元组结构体有着结构体名称提供的含义，但没有具体的字段名，只有字段的类型</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Color</span></span>(<span class="built_in">i32</span>, <span class="built_in">i32</span>, <span class="built_in">i32</span>);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Point</span></span>(<span class="built_in">i32</span>, <span class="built_in">i32</span>, <span class="built_in">i32</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> black = Color(<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">let</span> origin = Point(<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br></pre></td></tr></table></figure>
<h4 id="5-1-2-结构体数据的所有权">5.1.2 结构体数据的所有权</h4>
<ul>
<li>结构体可以直接存放自身拥有所有权的类型，如<code>String</code>等</li>
<li>结构体在存储<code>引用</code>、<code>slice</code>等没有自身所有权的类型时，需要用上生命周期</li>
</ul>
<h3 id="5-2-结构体引用和打印">5.2 结构体引用和打印</h3>
<h4 id="5-2-1-函数调用结构体">5.2.1 函数调用结构体</h4>
<p>函数引用结构体时，不需要获得其所有权，所以采用引用的方式调用:</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Rectangle</span></span> &#123;</span><br><span class="line">    width: <span class="built_in">u32</span>,</span><br><span class="line">    height: <span class="built_in">u32</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> rect1 = Rectangle &#123; width: <span class="number">30</span>, height: <span class="number">50</span> &#125;;</span><br><span class="line">    <span class="built_in">println!</span>(</span><br><span class="line">        <span class="string">&quot;The area of the rectangle is &#123;&#125; square pixels.&quot;</span>,</span><br><span class="line">        area(&amp;rect1)</span><br><span class="line">    );</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">area</span></span>(rectangle: &amp;Rectangle) -&gt; <span class="built_in">u32</span> &#123;</span><br><span class="line">    rectangle.width * rectangle.height</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="5-2-2-结构体打印">5.2.2 结构体打印</h4>
<p>需要使用派生trait</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#[derive(Debug)]</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Rectangle</span></span> &#123;</span><br><span class="line">    width: <span class="built_in">u32</span>,</span><br><span class="line">    height: <span class="built_in">u32</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> rect1 = Rectangle &#123; width: <span class="number">30</span>, height: <span class="number">50</span> &#125;;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;rect1 is &#123;:?&#125;&quot;</span>, rect1);</span><br><span class="line">    <span class="comment">// 或 println!(&quot;rect1 is &#123;:#?&#125;&quot;, rect1);</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="5-3-方法语法">5.3 方法语法</h3>
<p>使用关键字<code>impl</code>给结构体定义方法，可以避免另外定义函数</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#[derive(Debug)]</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Rectangle</span></span> &#123;</span><br><span class="line">    width: <span class="built_in">u32</span>,</span><br><span class="line">    height: <span class="built_in">u32</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span> Rectangle &#123;</span><br><span class="line">    <span class="comment">// 将self以不可变引用的方式调用</span></span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">area</span></span>(&amp;<span class="keyword">self</span>) -&gt; <span class="built_in">u32</span> &#123;</span><br><span class="line">        <span class="keyword">self</span>.width * <span class="keyword">self</span>.height</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> rect1 = Rectangle &#123; width: <span class="number">30</span>, height: <span class="number">50</span> &#125;;</span><br><span class="line">    <span class="built_in">println!</span>(</span><br><span class="line">        <span class="string">&quot;The area of the rectangle is &#123;&#125; square pixels.&quot;</span>,</span><br><span class="line">        rect1.area()</span><br><span class="line">    );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="5-3-1-关联函数">5.3.1 关联函数</h4>
<p>在<code>impl</code>块中定义不以<code>self</code>作为参数的函数，通常用作返回一个结构体实例的构造函数：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#[derive(Debug)]</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Rectangle</span></span> &#123;</span><br><span class="line">    width: <span class="built_in">u32</span>,</span><br><span class="line">    height: <span class="built_in">u32</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span> Rectangle &#123;</span><br><span class="line">    <span class="comment">// 返回一个正方形的实例</span></span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">square</span></span>(size: <span class="built_in">u32</span>) -&gt; Rectangle &#123;</span><br><span class="line">        Rectangle &#123; width: size, height: size &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>使用<code>let sq = Rectangle::square(3);</code>调用关联函数</li>
</ul>
<h2 id="Ch6-枚举和模式匹配">Ch6 枚举和模式匹配</h2>
<h3 id="6-1-定义枚举">6.1 定义枚举</h3>
<ul>
<li>以IP地址类型为例，通过<code>enum</code>定义一个枚举类型：</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">IpAddrKind</span></span> &#123;</span><br><span class="line">    V4(<span class="built_in">u8</span>, <span class="built_in">u8</span>, <span class="built_in">u8</span>, <span class="built_in">u8</span>),</span><br><span class="line">    V6(<span class="built_in">String</span>),</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>创建<code>IpAddrKind</code>实例：</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> four = IpAddrKind::V4(<span class="number">127.0</span>.<span class="number">0.1</span>);</span><br><span class="line"><span class="keyword">let</span> six = IpAddrKind::V6(<span class="built_in">String</span>::from(<span class="string">&quot;::1&quot;</span>));</span><br></pre></td></tr></table></figure>
<ul>
<li>枚举类型也可以像结构体一样使用<code>impl</code>为其定义方法</li>
</ul>
<h4 id="6-1-1-Option枚举">6.1.1 Option枚举</h4>
<ul>
<li>
<p><code>Option</code>是标准库定义的另一个枚举，且被包含在<code>preclude</code>中</p>
</li>
<li>
<p>Rust没有空值，但拥有<code>Option</code>枚举来编码存在或不存在</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">Option</span></span>&lt;T&gt; &#123;</span><br><span class="line">    <span class="literal">Some</span>(T),</span><br><span class="line">    <span class="literal">None</span>,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p><code>Some</code>可以包含任意类型的数据</p>
</li>
<li>
<p>使用<code>None</code>需要指定类型</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> some_number = <span class="literal">Some</span>(<span class="number">5</span>);</span><br><span class="line"><span class="keyword">let</span> some_string = <span class="literal">Some</span>(<span class="string">&quot;a string&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> absent_number: <span class="built_in">Option</span>&lt;<span class="built_in">i32</span>&gt; = <span class="literal">None</span>;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p><code>Option&lt;T&gt;</code>类型的值不能和<code>T</code>类型的值直接运算，必须提前进行转换，因此空值在使用前必须被检查</p>
</li>
</ul>
<h3 id="6-2-match控制流运算符">6.2 match控制流运算符</h3>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">Coin</span></span> &#123;</span><br><span class="line">   Penny,</span><br><span class="line">   Nickel,</span><br><span class="line">   Dime,</span><br><span class="line">   Quarter,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">value_in_cents</span></span>(coin: Coin) -&gt; <span class="built_in">u8</span> &#123;</span><br><span class="line">    <span class="keyword">match</span> coin &#123;</span><br><span class="line">        Coin::Penny =&gt; &#123;</span><br><span class="line">            <span class="built_in">println!</span>(<span class="string">&quot;Lucky penny!&quot;</span>);</span><br><span class="line">            <span class="number">1</span></span><br><span class="line">        &#125;,</span><br><span class="line">        Coin::Nickel =&gt; <span class="number">5</span>,</span><br><span class="line">        Coin::Dime =&gt; <span class="number">10</span>,</span><br><span class="line">        Coin::Quarter =&gt; <span class="number">25</span>,</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>每个分支相关联的代码是一个表达式，而表达式的结果值将作为整个<code>match</code>表达式的返回值</li>
</ul>
<h4 id="6-2-1-匹配Option-T">6.2.1 匹配Option&lt;T&gt;</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">plus_one</span></span>(x: <span class="built_in">Option</span>&lt;<span class="built_in">i32</span>&gt;) -&gt; <span class="built_in">Option</span>&lt;<span class="built_in">i32</span>&gt; &#123;</span><br><span class="line">    <span class="keyword">match</span> x &#123;</span><br><span class="line">        <span class="literal">None</span> =&gt; <span class="literal">None</span>,</span><br><span class="line">        <span class="literal">Some</span>(i) =&gt; <span class="literal">Some</span>(i + <span class="number">1</span>),</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> five = <span class="literal">Some</span>(<span class="number">5</span>);</span><br><span class="line"><span class="keyword">let</span> six = plus_one(five);</span><br><span class="line"><span class="keyword">let</span> none = plus_one(<span class="literal">None</span>);</span><br></pre></td></tr></table></figure>
<ul>
<li>用于空值处理</li>
<li>匹配是有穷的，必须覆盖变量的所有情况</li>
</ul>
<h4 id="6-2-2-通配符">6.2.2 _通配符</h4>
<ul>
<li>
<p>可以在match的所有分支的最后使用<code>_</code>来匹配剩余的所有情况</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> some_u8_value = <span class="number">0u8</span>;</span><br><span class="line"><span class="keyword">match</span> some_u8_value &#123;</span><br><span class="line">    <span class="number">1</span> =&gt; <span class="built_in">println!</span>(<span class="string">&quot;one&quot;</span>),</span><br><span class="line">    <span class="number">3</span> =&gt; <span class="built_in">println!</span>(<span class="string">&quot;three&quot;</span>),</span><br><span class="line">    <span class="number">5</span> =&gt; <span class="built_in">println!</span>(<span class="string">&quot;five&quot;</span>),</span><br><span class="line">    <span class="number">7</span> =&gt; <span class="built_in">println!</span>(<span class="string">&quot;seven&quot;</span>),</span><br><span class="line">    _ =&gt; (),</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="6-3-if-let-简单控制流">6.3 if let 简单控制流</h3>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> some_u8_value = <span class="literal">Some</span>(<span class="number">0u8</span>);</span><br><span class="line"><span class="keyword">if</span> <span class="keyword">let</span> <span class="literal">Some</span>(<span class="number">3</span>) = some_u8_value &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;three&quot;</span>);</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;other&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>可以用于替代只有两分支的<code>match</code>语句</li>
</ul>
<h2 id="Ch7-使用包、Crate和模块管理项目">Ch7 使用包、Crate和模块管理项目</h2>
<h3 id="7-1-包和crate">7.1 包和crate</h3>
<ul>
<li>crate是一个二进制项或者库</li>
<li>包 (package) 是提供一系列功能的一个或者多个 crate，一个包会包含有一个<code>Cargo.toml</code>文件，阐述如何去构建这些 crate
<ul>
<li>一个包中至多<strong>只能</strong>包含一个库 crate</li>
<li>一个包中可以包含任意多个二进制 crate</li>
<li>一个包中至少包含一个 crate，无论是库的还是二进制的</li>
</ul>
</li>
<li>使用<code>cargo new</code>创建项目时，<code>src/main.rs</code>就是一个与包同名的二进制 crate 的 crate根</li>
<li>通过将文件放在 <code>src/bin</code> 目录下，一个包可以拥有多个二进制 crate：每个 <code>src/bin</code> 下的文件都会被编译成一个独立的二进制 crate</li>
</ul>
<h3 id="7-2-模块">7.2 模块</h3>
<p>模块定义：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">mod</span> front_of_house &#123;</span><br><span class="line">    <span class="keyword">mod</span> hosting &#123;</span><br><span class="line">        <span class="function"><span class="keyword">fn</span> <span class="title">add_to_waitlist</span></span>() &#123;&#125;</span><br><span class="line">        <span class="function"><span class="keyword">fn</span> <span class="title">seat_at_table</span></span>() &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">mod</span> serving &#123;</span><br><span class="line">        <span class="function"><span class="keyword">fn</span> <span class="title">take_order</span></span>() &#123;&#125;</span><br><span class="line">        <span class="function"><span class="keyword">fn</span> <span class="title">server_order</span></span>() &#123;&#125;</span><br><span class="line">        <span class="function"><span class="keyword">fn</span> <span class="title">take_payment</span></span>() &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>对应的模块树：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">crate</span></span><br><span class="line"> └── front_of_house</span><br><span class="line">     ├── hosting</span><br><span class="line">     │   ├── add_to_waitlist</span><br><span class="line">     │   └── seat_at_table</span><br><span class="line">     └── serving</span><br><span class="line">         ├── take_order</span><br><span class="line">         ├── serve_order</span><br><span class="line">         └── take_payment</span><br></pre></td></tr></table></figure>
<h3 id="7-3-引用模块树中项的路径">7.3 引用模块树中项的路径</h3>
<p>路径的两种形式，都是通过<code>::</code>连接：</p>
<ul>
<li>**绝对路径 ** 从 crate 根开始，以 crate 名或者字面值 <code>crate</code> 开头。</li>
<li><strong>相对路径</strong> 从当前模块开始，以 <code>self</code>、<code>super</code> 或当前模块的标识符开头。</li>
</ul>
<h4 id="7-3-1-使用pub关键字暴露路径">7.3.1 使用pub关键字暴露路径</h4>
<ul>
<li>Rust 中默认所有项（函数、方法、结构体、枚举、模块和常量）都是私有的，父模块不能使用子模块的私有项，但子模块可以使用父模块中的项，同级的两个模块可以互相引用</li>
<li>当父模块需要使用子模块的项的，需要在子模块中将其声明为<code>pub</code></li>
</ul>
<h4 id="7-3-2-使用super起始的相对路径">7.3.2 使用super起始的相对路径</h4>
<ul>
<li><code>super</code>相当于文件系统中的<code>..</code>，即当前模块的父模块</li>
</ul>
<h4 id="7-3-3-创建公有的结构体和枚举">7.3.3 创建公有的结构体和枚举</h4>
<ul>
<li>如果在一个结构体定义的前面使用了 <code>pub</code> ，这个结构体会变成公有的，但是这个结构体的字段仍然是私有的</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">mod</span> back_of_house &#123;</span><br><span class="line">    <span class="keyword">pub</span> <span class="class"><span class="keyword">struct</span> <span class="title">Breakfast</span></span> &#123;</span><br><span class="line">        <span class="keyword">pub</span> toast: <span class="built_in">String</span>,</span><br><span class="line">        seasonal_fruit: <span class="built_in">String</span>,</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">impl</span> Breakfast &#123;</span><br><span class="line">        <span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">summer</span></span>(toast: &amp;<span class="built_in">str</span>) -&gt; Breakfast &#123;</span><br><span class="line">            Breakfast &#123;</span><br><span class="line">                toast: <span class="built_in">String</span>::from(toast),</span><br><span class="line">                seasonal_fruit: <span class="built_in">String</span>::from(<span class="string">&quot;peaches&quot;</span>),</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">eat_at_restaurant</span></span>() &#123;</span><br><span class="line">    <span class="comment">// Order a breakfast in the summer with Rye toast</span></span><br><span class="line">    <span class="keyword">let</span> <span class="keyword">mut</span> meal = back_of_house::Breakfast::summer(<span class="string">&quot;Rye&quot;</span>);</span><br><span class="line">    <span class="comment">// Change our mind about what bread we&#x27;d like</span></span><br><span class="line">    meal.toast = <span class="built_in">String</span>::from(<span class="string">&quot;Wheat&quot;</span>);</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;I&#x27;d like &#123;&#125; toast please&quot;</span>, meal.toast);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>因为 <code>back_of_house::Breakfast</code> 具有私有字段，所以这个结构体需要提供一个公共的关联函数来构造实例 <code>Breakfast</code>，否则无法在 <code>eat_at_restaurant</code> 中创建实例</li>
</ul>
<h3 id="7-4-use关键字">7.4 use关键字</h3>
<ul>
<li>使用use关键字可以简化模块中项的调用：</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">mod</span> front_of_house &#123;</span><br><span class="line">    <span class="keyword">pub</span> <span class="keyword">mod</span> hosting &#123;</span><br><span class="line">        <span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">add_to_waitlist</span></span>() &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> crate::front_of_house::hosting;  <span class="comment">// 绝对路径</span></span><br><span class="line"><span class="comment">// 或 use front_of_house::hosting;  相对路径</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">eat_at_restaurant</span></span>() &#123;</span><br><span class="line">    hosting::add_to_waitlist();</span><br><span class="line">    hosting::add_to_waitlist();</span><br><span class="line">    hosting::add_to_waitlist();</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>
<p>可以使用 <code>as</code> 关键字提供新名称</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::fmt::<span class="built_in">Result</span>;</span><br><span class="line"><span class="keyword">use</span> std::io::<span class="built_in">Result</span> <span class="keyword">as</span> IoResult;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">function1</span></span>() -&gt; <span class="built_in">Result</span> &#123;</span><br><span class="line">    <span class="comment">// --snip--</span></span><br><span class="line">#     <span class="literal">Ok</span>(())</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">function2</span></span>() -&gt; IoResult&lt;()&gt; &#123;</span><br><span class="line">    <span class="comment">// --snip--</span></span><br><span class="line">#     <span class="literal">Ok</span>(())</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>当使用 <code>use</code> 关键字将名称导入作用域时，在新作用域中可用的名称是私有的，可以使用 <code>pub use</code> 重导出，使得名称可以引入任何代码的作用域中</p>
</li>
</ul>
<h4 id="7-4-1-使用嵌套路径精简代码">7.4.1 使用嵌套路径精简代码</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::cmp::Ordering;</span><br><span class="line"><span class="keyword">use</span> std::io;</span><br><span class="line"><span class="comment">// 可以精简为：</span></span><br><span class="line"><span class="keyword">use</span> std::&#123;cmp::Ordering, io&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> std::io;</span><br><span class="line"><span class="keyword">use</span> std::io::Write;</span><br><span class="line"><span class="comment">// 可以精简为：</span></span><br><span class="line"><span class="keyword">use</span> std::io::&#123;<span class="keyword">self</span>, Write&#125;;</span><br></pre></td></tr></table></figure>
<h4 id="7-4-2-glob运算符">7.4.2 glob运算符</h4>
<p>如果希望将一个路径下<strong>所有</strong>公有项引入作用域，可以指定路径后跟 <code>*</code></p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::collections::*;</span><br></pre></td></tr></table></figure>
<h3 id="7-5-将模块分割进不同文件">7.5 将模块分割进不同文件</h3>
<p>先使用如下语句引入模块：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">mod</span> front_of_house;</span><br></pre></td></tr></table></figure>
<h2 id="Ch8-常见集合">Ch8 常见集合</h2>
<h3 id="8-1-vector">8.1 vector</h3>
<ul>
<li>在一个单独的数据结构中储存多于一个的值，它在内存中彼此相邻地排列所有的值</li>
<li>vector 只能储存相同类型的值</li>
</ul>
<h4 id="8-1-1-新建vector">8.1.1 新建vector</h4>
<ul>
<li>
<p>新建空vector时需要指明类型</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> v: <span class="built_in">Vec</span>&lt;<span class="built_in">i32</span>&gt; = <span class="built_in">Vec</span>::new();</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>使用 <code>vec!</code> 宏来定义含有初值的vector</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> v = <span class="built_in">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="8-1-2-vector添加元素">8.1.2 vector添加元素</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> v = <span class="built_in">Vec</span>::new();</span><br><span class="line"></span><br><span class="line">v.push(<span class="number">5</span>);</span><br><span class="line">v.push(<span class="number">6</span>);</span><br></pre></td></tr></table></figure>
<ul>
<li>当vector离开作用域时，会连同其元素全部销毁</li>
</ul>
<h4 id="8-1-3-读取vector元素">8.1.3 读取vector元素</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> v = <span class="built_in">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>];</span><br></pre></td></tr></table></figure>
<ul>
<li>
<p>使用索引访问，若越界，则会报错崩溃(适用于访问边界严格的vector)</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> third: &amp;<span class="built_in">i32</span> = &amp;v[<span class="number">2</span>];</span><br><span class="line"><span class="built_in">println!</span>(<span class="string">&quot;The third element is &#123;&#125;&quot;</span>, third);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>使用 <code>get</code> 方法返回一个 <code>Option&lt;&amp;T&gt;</code>，若越界，则会返回None(适用于vector索引可能由用户输入而越界)</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">match</span> v.get(<span class="number">2</span>) &#123;</span><br><span class="line">    <span class="literal">Some</span>(third) =&gt; <span class="built_in">println!</span>(<span class="string">&quot;The third element is &#123;&#125;&quot;</span>, third),</span><br><span class="line">    <span class="literal">None</span> =&gt; <span class="built_in">println!</span>(<span class="string">&quot;There is no third element.&quot;</span>),</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>当获取了vector的一个元素的不可变引用后，不能在其末尾添加元素，如下代码<code>非法</code>：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> v = <span class="built_in">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> first = &amp;v[<span class="number">0</span>];</span><br><span class="line">v.push(<span class="number">6</span>);</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="8-1-4-遍历vector中的元素">8.1.4 遍历vector中的元素</h4>
<ul>
<li>
<p>遍历不可变引用</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> v = <span class="built_in">vec!</span>[<span class="number">100</span>, <span class="number">32</span>, <span class="number">57</span>];</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> &amp;v &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;&#123;&#125;&quot;</span>, i);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>遍历可变引用</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> v = <span class="built_in">vec!</span>[<span class="number">100</span>, <span class="number">32</span>, <span class="number">57</span>];</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> &amp;<span class="keyword">mut</span> v &#123;</span><br><span class="line">    *i += <span class="number">50</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="8-1-5-结合枚举来存储多种类型">8.1.5 结合枚举来存储多种类型</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">SpreadsheetCell</span></span> &#123;</span><br><span class="line">    Int(<span class="built_in">i32</span>),</span><br><span class="line">    Float(<span class="built_in">f64</span>),</span><br><span class="line">    Text(<span class="built_in">String</span>),</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> row = <span class="built_in">vec!</span>[</span><br><span class="line">    SpreadsheetCell::Int(<span class="number">3</span>),</span><br><span class="line">    SpreadsheetCell::Text(<span class="built_in">String</span>::from(<span class="string">&quot;blue&quot;</span>)),</span><br><span class="line">    SpreadsheetCell::Float(<span class="number">10.12</span>),</span><br><span class="line">];</span><br></pre></td></tr></table></figure>
<h3 id="8-2-字符串">8.2 字符串</h3>
<h4 id="8-2-1-新建字符串">8.2.1 新建字符串</h4>
<ul>
<li>
<p>新建空字符串</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> s = <span class="built_in">String</span>::new();</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>往空字符串中装载数据</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="string">&quot;initial contents&quot;</span>.to_string();</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>新建有初始值的字符串</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="built_in">String</span>::from(<span class="string">&quot;initial contents&quot;</span>);</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="8-2-2-更新字符串">8.2.2 更新字符串</h4>
<ul>
<li>
<p>使用 <code>push_str</code> 方法来附加字符串 slice</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> s = <span class="built_in">String</span>::from(<span class="string">&quot;foo&quot;</span>);</span><br><span class="line">s.push_str(<span class="string">&quot;bar&quot;</span>);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>使用 <code>push</code> 附加一个字符</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> s = <span class="built_in">String</span>::from(<span class="string">&quot;lo&quot;</span>);</span><br><span class="line">s.push(<span class="string">&#x27;l&#x27;</span>);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>使用 <code>+</code> 运算符</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> s1 = <span class="built_in">String</span>::from(<span class="string">&quot;Hello, &quot;</span>);</span><br><span class="line"><span class="keyword">let</span> s2 = <span class="built_in">String</span>::from(<span class="string">&quot;world!&quot;</span>);</span><br><span class="line"><span class="keyword">let</span> s3 = s1 + &amp;s2; <span class="comment">// 注意 s1 被移动了，不能继续使用</span></span><br></pre></td></tr></table></figure>
</li>
<li>
<p>使用 <code>format!</code> 宏</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> s1 = <span class="built_in">String</span>::from(<span class="string">&quot;tic&quot;</span>);</span><br><span class="line"><span class="keyword">let</span> s2 = <span class="built_in">String</span>::from(<span class="string">&quot;tac&quot;</span>);</span><br><span class="line"><span class="keyword">let</span> s3 = <span class="built_in">String</span>::from(<span class="string">&quot;toe&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> s = <span class="built_in">format!</span>(<span class="string">&quot;&#123;&#125;-&#123;&#125;-&#123;&#125;&quot;</span>, s1, s2, s3);</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="8-2-3-索引字符串">8.2.3 索引字符串</h4>
<p>Rust的 <code>String</code> 字符串不支持索引单个值，但能够创建字符串slice</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> hello = <span class="string">&quot;Здравствуйте&quot;</span>;</span><br><span class="line"><span class="keyword">let</span> s = &amp;hello[<span class="number">0</span>..<span class="number">4</span>];</span><br></pre></td></tr></table></figure>
<h4 id="8-2-4-遍历字符串">8.2.4 遍历字符串</h4>
<ul>
<li>
<p>遍历每个元素（每个元素可能不止一个字节）</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> c <span class="keyword">in</span> <span class="string">&quot;नमस्ते&quot;</span>.chars() &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;&#123;&#125;&quot;</span>, c);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>遍历每个原始字节</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> b <span class="keyword">in</span> <span class="string">&quot;नमस्ते&quot;</span>.bytes() &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;&#123;&#125;&quot;</span>, b);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="8-3-哈希map">8.3 哈希map</h3>
<p><code>HashMap&lt;K, V&gt;</code> 类型储存了一个键类型 <code>K</code> 对应一个值类型 <code>V</code> 的映射</p>
<h4 id="8-3-1-新建一个哈希map">8.3.1 新建一个哈希map</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::collections::HashMap;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 新建一个空的Hashmap</span></span><br><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> scores = HashMap::new();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 插入键值对</span></span><br><span class="line">scores.insert(<span class="built_in">String</span>::from(<span class="string">&quot;Blue&quot;</span>), <span class="number">10</span>);</span><br><span class="line">scores.insert(<span class="built_in">String</span>::from(<span class="string">&quot;Yellow&quot;</span>), <span class="number">50</span>);</span><br></pre></td></tr></table></figure>
<ul>
<li>哈希 map 将它们的数据储存在堆上</li>
<li>所有的键必须是相同类型，值也必须都是相同类型</li>
</ul>
<p>也可以通过vector的 <code>collect</code> 方法创建</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::collections::HashMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> teams  = <span class="built_in">vec!</span>[<span class="built_in">String</span>::from(<span class="string">&quot;Blue&quot;</span>), <span class="built_in">String</span>::from(<span class="string">&quot;Yellow&quot;</span>)];</span><br><span class="line"><span class="keyword">let</span> initial_scores = <span class="built_in">vec!</span>[<span class="number">10</span>, <span class="number">50</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> scores: HashMap&lt;_, _&gt; = teams.iter().zip(initial_scores.iter()).collect();</span><br></pre></td></tr></table></figure>
<h4 id="8-3-2-哈希map和所有权">8.3.2 哈希map和所有权</h4>
<ul>
<li>对于像 <code>i32</code> 这样的实现了 <code>Copy</code> trait 的类型，其值可以拷贝进哈希 map</li>
<li>对于像 <code>String</code> 这样拥有所有权的值，其值将被移动而哈希 map 会成为这些值的所有者</li>
</ul>
<h4 id="8-3-3-访问哈希map中的值">8.3.3 访问哈希map中的值</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> team_name = <span class="built_in">String</span>::from(<span class="string">&quot;Blue&quot;</span>);</span><br><span class="line"><span class="keyword">let</span> score = scores.get(&amp;team_name);</span><br></pre></td></tr></table></figure>
<ul>
<li><code>get</code> 方法返回的 <code>score</code> 是 <code>Option&lt;T&gt;</code> 类型</li>
</ul>
<h4 id="8-3-4-遍历哈希map">8.3.4 遍历哈希map</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (key, value) <span class="keyword">in</span> &amp;scores &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;&#123;&#125;: &#123;&#125;&quot;</span>, key, value);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="8-3-5-更新哈希map">8.3.5 更新哈希map</h4>
<ul>
<li>
<p>使用相同的键插入不同的值，会覆盖旧值</p>
</li>
<li>
<p>使用 <code>entry</code> 方法，只有在键没有对应的值存在的时候插入</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">scores.entry(<span class="built_in">String</span>::from(<span class="string">&quot;Yellow&quot;</span>)).or_insert(<span class="number">50</span>);</span><br><span class="line">scores.entry(<span class="built_in">String</span>::from(<span class="string">&quot;Blue&quot;</span>)).or_insert(<span class="number">50</span>);</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>根据旧值更新一个值</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::collections::HashMap;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 统计单词出现的次数</span></span><br><span class="line"><span class="keyword">let</span> text = <span class="string">&quot;hello world wonderful world&quot;</span>;</span><br><span class="line"><span class="keyword">let</span> <span class="keyword">mut</span> map = HashMap::new();</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> word <span class="keyword">in</span> text.split_whitespace() &#123;</span><br><span class="line">    <span class="keyword">let</span> count = map.entry(word).or_insert(<span class="number">0</span>);</span><br><span class="line">    *count += <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">println!</span>(<span class="string">&quot;&#123;:?&#125;&quot;</span>, map);</span><br></pre></td></tr></table></figure>
<ul>
<li><code>or_insert</code> 方法事实上会返回这个键的值的一个可变引用（<code>&amp;mut V</code>）</li>
</ul>
</li>
</ul>
<h2 id="Ch9-错误处理">Ch9 错误处理</h2>
<h3 id="9-1-panic-与不可恢复的错误">9.1 panic!与不可恢复的错误</h3>
<p>遇到错误时，Rust 有 <code>panic!</code>宏，当执行这个宏时，程序会打印出一个错误信息，展开并清理栈数据，然后接着退出</p>
<h4 id="9-1-1-backtrace">9.1.1 backtrace</h4>
<ul>
<li>
<p>backtrace 是一个执行到目前位置所有被调用的函数的列表</p>
</li>
<li>
<p>使用backtrace来找到自己写的代码中错误出在哪一行</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ RUST_BACKTRACE=1 cargo run</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="9-2-Result与可恢复的错误">9.2 Result与可恢复的错误</h3>
<p><code>Result</code> 枚举：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">Result</span></span>&lt;T, E&gt; &#123;</span><br><span class="line">    <span class="literal">Ok</span>(T),</span><br><span class="line">    <span class="literal">Err</span>(E),</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li><code>T</code> 代表成功时返回的 <code>Ok</code> 成员中的数据的类型</li>
<li><code>E</code> 代表失败时返回的 <code>Err</code> 成员中的错误的类型</li>
</ul>
<h4 id="9-2-1-匹配不同的错误">9.2.1 匹配不同的错误</h4>
<ul>
<li>使用 <code>match</code> 代码比较冗长，且较难理解</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::fs::File;</span><br><span class="line"><span class="keyword">use</span> std::io::ErrorKind;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> f = File::open(<span class="string">&quot;hello.txt&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> f = <span class="keyword">match</span> f &#123;</span><br><span class="line">        <span class="literal">Ok</span>(file) =&gt; file,</span><br><span class="line">        <span class="literal">Err</span>(error) =&gt; <span class="keyword">match</span> error.kind() &#123;</span><br><span class="line">            ErrorKind::NotFound =&gt; <span class="keyword">match</span> File::create(<span class="string">&quot;hello.txt&quot;</span>) &#123;</span><br><span class="line">                <span class="literal">Ok</span>(fc) =&gt; fc,</span><br><span class="line">                <span class="literal">Err</span>(e) =&gt; <span class="built_in">panic!</span>(<span class="string">&quot;Problem creating the file: &#123;:?&#125;&quot;</span>, e),</span><br><span class="line">            &#125;,</span><br><span class="line">            other_error =&gt; <span class="built_in">panic!</span>(<span class="string">&quot;Problem opening the file: &#123;:?&#125;&quot;</span>, </span><br><span class="line">                					other_error),</span><br><span class="line">        &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="9-2-2-unwrap">9.2.2 unwrap</h4>
<ul>
<li>如果 <code>Result</code> 值是成员 <code>Ok</code>，<code>unwrap</code> 会返回 <code>Ok</code> 中的值</li>
<li>如果 <code>Result</code> 是成员 <code>Err</code>，<code>unwrap</code> 会为我们调用 <code>panic!</code></li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::fs::File;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> f = File::open(<span class="string">&quot;hello.txt&quot;</span>).unwrap();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="9-2-3-expect">9.2.3 expect</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::fs::File;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> f = File::open(<span class="string">&quot;hello.txt&quot;</span>).expect(<span class="string">&quot;Failed to open hello.txt&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>使用方法类似 <code>unwrap</code> ，但是可以自己指定显示的错误信息</li>
</ul>
<h4 id="9-2-4-传播错误">9.2.4 传播错误</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::io;</span><br><span class="line"><span class="keyword">use</span> std::io::Read;</span><br><span class="line"><span class="keyword">use</span> std::fs::File;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">read_username_from_file</span></span>() -&gt; <span class="built_in">Result</span>&lt;<span class="built_in">String</span>, io::Error&gt; &#123;</span><br><span class="line">    <span class="comment">// 若文件打开失败，函数会返回相应的错误</span></span><br><span class="line">    <span class="keyword">let</span> <span class="keyword">mut</span> f = File::open(<span class="string">&quot;hello.txt&quot;</span>)?;</span><br><span class="line">    <span class="keyword">let</span> <span class="keyword">mut</span> s = <span class="built_in">String</span>::new();</span><br><span class="line">    <span class="comment">// 若文件内容写入字符串失败，函数会返回相应的错误</span></span><br><span class="line">    f.read_to_string(&amp;<span class="keyword">mut</span> s)?;</span><br><span class="line">    <span class="comment">// 若函数执行完成没有出错，则返回Ok</span></span><br><span class="line">    <span class="literal">Ok</span>(s)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Rust提供了<code>fs::read_to_string</code> 的函数来简化从文件读取到一个字符串中的操作：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::io;</span><br><span class="line"><span class="keyword">use</span> std::fs;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">read_username_from_file</span></span>() -&gt; <span class="built_in">Result</span>&lt;<span class="built_in">String</span>, io::Error&gt; &#123;</span><br><span class="line">    fs::read_to_string(<span class="string">&quot;hello.txt&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="9-3-panic-的使用场景">9.3 panic!的使用场景</h3>
<p>在当有可能会导致有害状态的情况下建议使用 <code>panic!</code> —— 在这里，有害状态是指当一些假设、保证、协议或不可变性被打破的状态，例如无效的值、自相矛盾的值或者被传递了不存在的值 —— 外加如下几种情况：</p>
<ul>
<li>有害状态并不包含 <strong>预期</strong> 会偶尔发生的错误</li>
<li>之后的代码的运行依赖于处于这种有害状态</li>
<li>当没有可行的手段来将有害状态信息编码进所使用的类型中的情况</li>
</ul>
<h2 id="Ch10-泛型、trait和生命周期">Ch10 泛型、trait和生命周期</h2>
<h3 id="10-1-泛型">10.1 泛型</h3>
<p>使用泛型为像函数签名或结构体这样的项创建定义，这样它们就可以用于多种不同的具体数据类型</p>
<h4 id="10-1-1-在函数定义中使用泛型">10.1.1 在函数定义中使用泛型</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">largest</span></span>&lt;T&gt;(list: &amp;[T]) -&gt; T &#123;</span><br><span class="line">    <span class="keyword">let</span> <span class="keyword">mut</span> largest = list[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> &amp;item <span class="keyword">in</span> list.iter() &#123;</span><br><span class="line">        <span class="keyword">if</span> item &gt; largest &#123;</span><br><span class="line">            largest = item;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    largest</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>当在函数签名中使用一个类型参数时，必须在使用它之前就声明它，所以需要在函数名称之后写上 <code>&lt;T&gt;</code></li>
</ul>
<h4 id="10-1-2-结构体定义中的泛型">10.1.2 结构体定义中的泛型</h4>
<ul>
<li>字段 <code>x</code> 和 <code>y</code> 必须是相同的类型</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Point</span></span>&lt;T&gt; &#123;</span><br><span class="line">    x: T,</span><br><span class="line">    y: T,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> integer = Point &#123; x: <span class="number">5</span>, y: <span class="number">10</span> &#125;;</span><br><span class="line">    <span class="keyword">let</span> float = Point &#123; x: <span class="number">1.0</span>, y: <span class="number">4.0</span> &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>字段 <code>x</code> 和 <code>y</code> 可以是不同的类型</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Point</span></span>&lt;T, U&gt; &#123;</span><br><span class="line">    x: T,</span><br><span class="line">    y: U,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> both_integer = Point &#123; x: <span class="number">5</span>, y: <span class="number">10</span> &#125;;</span><br><span class="line">    <span class="keyword">let</span> both_float = Point &#123; x: <span class="number">1.0</span>, y: <span class="number">4.0</span> &#125;;</span><br><span class="line">    <span class="keyword">let</span> integer_and_float = Point &#123; x: <span class="number">5</span>, y: <span class="number">4.0</span> &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="10-1-3-枚举定义中的泛型">10.1.3 枚举定义中的泛型</h4>
<p><code>Option&lt;T&gt;</code> 枚举：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">Option</span></span>&lt;T&gt; &#123;</span><br><span class="line">    <span class="literal">Some</span>(T),</span><br><span class="line">    <span class="literal">None</span>,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><code>Result&lt;T, E&gt;</code> 枚举：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">Result</span></span>&lt;T, E&gt; &#123;</span><br><span class="line">    <span class="literal">Ok</span>(T),</span><br><span class="line">    <span class="literal">Err</span>(E),</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="10-1-4-方法定义中的泛型">10.1.4 方法定义中的泛型</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Point</span></span>&lt;T&gt; &#123;</span><br><span class="line">    x: T,</span><br><span class="line">    y: T,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span>&lt;T&gt; Point&lt;T&gt; &#123;</span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">x</span></span>(&amp;<span class="keyword">self</span>) -&gt; &amp;T &#123;</span><br><span class="line">        &amp;<span class="keyword">self</span>.x</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> p = Point &#123; x: <span class="number">5</span>, y: <span class="number">10</span> &#125;;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;p.x = &#123;&#125;&quot;</span>, p.x());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>在 <code>Point&lt;T&gt;</code> 结构体上实现方法 <code>x</code>，它返回 <code>T</code> 类型的字段 <code>x</code> 的引用</li>
<li>必须在 <code>impl</code> 后面声明 <code>T</code>，这样 Rust 就知道 <code>Point</code> 的尖括号中的类型是泛型而不是具体类型</li>
</ul>
<h4 id="10-1-5-泛型代码的性能">10.1.5 泛型代码的性能</h4>
<ul>
<li>Rust 实现了泛型，使得使用泛型类型参数的代码相比使用具体类型并没有任何速度上的损失</li>
<li>Rust 通过在编译时进行泛型代码的<strong>单态化</strong>来保证效率，即在编译时填充泛型所使用的具体类型，从而将通用代码转换为特定代码</li>
</ul>
<h3 id="10-2-trait：定义共享的行为">10.2 trait：定义共享的行为</h3>
<p><em>trait</em> 告诉 Rust 编译器某个特定类型拥有可能与其他类型共享的功能</p>
<h4 id="10-2-1-定义并使用trait">10.2.1 定义并使用trait</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">pub</span> <span class="class"><span class="keyword">trait</span> <span class="title">Summary</span></span> &#123;</span><br><span class="line">    <span class="comment">// 实现这个 trait 的类型所需要的行为的方法签名</span></span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">summarize</span></span>(&amp;<span class="keyword">self</span>) -&gt; <span class="built_in">String</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">pub</span> <span class="class"><span class="keyword">struct</span> <span class="title">NewsArticle</span></span> &#123;</span><br><span class="line">    <span class="keyword">pub</span> headline: <span class="built_in">String</span>,</span><br><span class="line">    <span class="keyword">pub</span> location: <span class="built_in">String</span>,</span><br><span class="line">    <span class="keyword">pub</span> author: <span class="built_in">String</span>,</span><br><span class="line">    <span class="keyword">pub</span> content: <span class="built_in">String</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在impl关键字之后，提供需要实现trait的名称，接着是for和需要实现trait的类型的名称</span></span><br><span class="line"><span class="keyword">impl</span> Summary <span class="keyword">for</span> NewsArticle &#123;</span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">summarize</span></span>(&amp;<span class="keyword">self</span>) -&gt; <span class="built_in">String</span> &#123;</span><br><span class="line">        <span class="built_in">format!</span>(<span class="string">&quot;&#123;&#125;, by &#123;&#125; (&#123;&#125;)&quot;</span>, <span class="keyword">self</span>.headline, <span class="keyword">self</span>.author, <span class="keyword">self</span>.location)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">pub</span> <span class="class"><span class="keyword">struct</span> <span class="title">Tweet</span></span> &#123;</span><br><span class="line">    <span class="keyword">pub</span> username: <span class="built_in">String</span>,</span><br><span class="line">    <span class="keyword">pub</span> content: <span class="built_in">String</span>,</span><br><span class="line">    <span class="keyword">pub</span> reply: <span class="built_in">bool</span>,</span><br><span class="line">    <span class="keyword">pub</span> retweet: <span class="built_in">bool</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span> Summary <span class="keyword">for</span> Tweet &#123;</span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">summarize</span></span>(&amp;<span class="keyword">self</span>) -&gt; <span class="built_in">String</span> &#123;</span><br><span class="line">        <span class="built_in">format!</span>(<span class="string">&quot;&#123;&#125;: &#123;&#125;&quot;</span>, <span class="keyword">self</span>.username, <span class="keyword">self</span>.content)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>只有当 trait 或者要实现 trait 的类型位于 crate 的本地作用域时，才能为该类型实现 trait</li>
<li>不能为外部类型实现外部 trait：例如，不能在 <code>aggregator</code> crate 中为 <code>Vec&lt;T&gt;</code> 实现 <code>Display</code> trait。这是因为 <code>Display</code> 和 <code>Vec&lt;T&gt;</code> 都定义于标准库中，它们并不位于 <code>aggregator</code> crate 本地作用域中</li>
</ul>
<h4 id="10-2-2-默认实现">10.2.2 默认实现</h4>
<p>有时为 trait 中的某些或全部方法提供默认的行为，而不是在每个类型的每个实现中都定义自己的行为是很有用的。这样当为某个特定类型实现 trait 时，可以选择保留或重载每个方法的默认行为</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// trait提供默认实现</span></span><br><span class="line"><span class="keyword">pub</span> <span class="class"><span class="keyword">trait</span> <span class="title">Summary</span></span> &#123;</span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">summarize</span></span>(&amp;<span class="keyword">self</span>) -&gt; <span class="built_in">String</span> &#123;</span><br><span class="line">        <span class="built_in">String</span>::from(<span class="string">&quot;(Read more...)&quot;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="10-2-3-trait作为参数">10.2.3 trait作为参数</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">notify</span></span>(item: <span class="keyword">impl</span> Summary) &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;Breaking news! &#123;&#125;&quot;</span>, item.summarize());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>对于 <code>item</code> 参数，指定了 <code>impl</code> 关键字和 trait 名称，而不是具体的类型。该参数支持任何实现了指定 trait 的类型。在 <code>notify</code> 函数体中，可以调用任何来自 <code>Summary</code> trait 的方法，比如 <code>summarize</code></p>
<ul>
<li>
<p>使用trait bound重写上面的函数</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">notify</span></span>&lt;T: Summary&gt;(item: T) &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;Breaking news! &#123;&#125;&quot;</span>, item.summarize());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>
<p>trait bound适合函数传入多个相同类型的参数</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// item1和item2的类型可以不同，只要它们都实现了Summary</span></span><br><span class="line"><span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">notify</span></span>(item1: <span class="keyword">impl</span> Summary, item2: <span class="keyword">impl</span> Summary) </span><br><span class="line">    </span><br><span class="line"><span class="comment">// item1和item2的类型必须相同</span></span><br><span class="line"><span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">notify</span></span>&lt;T: Summary&gt;(item1: T, item2: T)</span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
<li>
<p>指定多个trait bound</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">notify</span></span>(item: <span class="keyword">impl</span> Summary + Display)</span><br><span class="line"><span class="comment">// 或</span></span><br><span class="line"><span class="keyword">pub</span> <span class="function"><span class="keyword">fn</span> <span class="title">notify</span></span>&lt;T: Summary + Display&gt;(item: T)</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>通过 <code>where</code> 简化trait bound</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">some_function</span></span>&lt;T, U&gt;(t: T, u: U) -&gt; <span class="built_in">i32</span></span><br><span class="line">    <span class="keyword">where</span> T: Display + <span class="built_in">Clone</span>,</span><br><span class="line">          U: <span class="built_in">Clone</span> + <span class="built_in">Debug</span></span><br><span class="line">&#123;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="10-2-4-返回trait类型">10.2.4 返回trait类型</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">returns_summarizable</span></span>() -&gt; <span class="keyword">impl</span> Summary &#123;</span><br><span class="line">    Tweet &#123;</span><br><span class="line">        username: <span class="built_in">String</span>::from(<span class="string">&quot;horse_ebooks&quot;</span>),</span><br><span class="line">        content: <span class="built_in">String</span>::from(<span class="string">&quot;of course, as you probably already know, people&quot;</span>),</span><br><span class="line">        reply: <span class="literal">false</span>,</span><br><span class="line">        retweet: <span class="literal">false</span>,</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>通过使用 <code>impl Summary</code> 作为返回值类型，我们指定了 <code>returns_summarizable</code> 函数返回某个实现了 <code>Summary</code> trait 的类型，但是不确定其具体的类型</li>
<li>只适用于返回单一类型的情况，如果有分支结构，每个分支返回不同类型，则编译不能通过</li>
</ul>
<h3 id="10-3-生命周期与引用有效性">10.3 生命周期与引用有效性</h3>
<h4 id="10-3-1-生命周期防止悬垂引用">10.3.1 生命周期防止悬垂引用</h4>
<ul>
<li>Rust 编译器有一个<strong>借用检查器</strong>，它比较作用域来确保所有的借用都是有效的</li>
<li>避免了引用比数据的生命周期短的情况</li>
</ul>
<h4 id="10-3-2-函数的泛型生命周期">10.3.2 函数的泛型生命周期</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> string1 = <span class="built_in">String</span>::from(<span class="string">&quot;abcd&quot;</span>);</span><br><span class="line">    <span class="keyword">let</span> string2 = <span class="string">&quot;xyz&quot;</span>;</span><br><span class="line">    <span class="keyword">let</span> result = longest(string1.as_str(), string2);</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;The longest string is &#123;&#125;&quot;</span>, result);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">longest</span></span>(x: &amp;<span class="built_in">str</span>, y: &amp;<span class="built_in">str</span>) -&gt; &amp;<span class="built_in">str</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> x.len() &gt; y.len() &#123;</span><br><span class="line">        x</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        y</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>返回值需要一个泛型生命周期参数，因为 Rust 并不知道将要返回的引用是指向 <code>x</code> 或 <code>y</code></li>
</ul>
<h5 id="生命周期注解语法">生命周期注解语法</h5>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&amp;<span class="built_in">i32</span>        <span class="comment">// 引用</span></span><br><span class="line">&amp;<span class="symbol">&#x27;a</span> <span class="built_in">i32</span>     <span class="comment">// 带有显式生命周期的引用</span></span><br><span class="line">&amp;<span class="symbol">&#x27;a</span> <span class="keyword">mut</span> <span class="built_in">i32</span> <span class="comment">// 带有显式生命周期的可变引用</span></span><br></pre></td></tr></table></figure>
<ul>
<li>当有两个或以上的引用参数的生命周期注解都定义为 <code>&amp;'a i32</code> ，则这些参数的生命周期必须与这泛型生命周期一样长</li>
</ul>
<h5 id="函数签名中的生命周期注解">函数签名中的生命周期注解</h5>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 重写上面的longest函数，指定了签名中所有的引用必须有相同的生命周期&#x27;a</span></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">longest</span></span>&lt;<span class="symbol">&#x27;a</span>&gt;(x: &amp;<span class="symbol">&#x27;a</span> <span class="built_in">str</span>, y: &amp;<span class="symbol">&#x27;a</span> <span class="built_in">str</span>) -&gt; &amp;<span class="symbol">&#x27;a</span> <span class="built_in">str</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> x.len() &gt; y.len() &#123;</span><br><span class="line">        x</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        y</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="10-3-3-结构体定义生命周期注解">10.3.3 结构体定义生命周期注解</h4>
<p>有生命周期注解的结构体可以存放引用</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ImportantExcerpt</span></span>&lt;<span class="symbol">&#x27;a</span>&gt; &#123;</span><br><span class="line">    part: &amp;<span class="symbol">&#x27;a</span> <span class="built_in">str</span>,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="10-3-4-生命周期省略">10.3.4 生命周期省略</h4>
<p>编译器采用三条规则来判断引用何时不需要明确的注解，这些规则适用于 <code>fn</code> 定义，以及 <code>impl</code> 块</p>
<ul>
<li>每一个是引用的参数都有它自己的生命周期参数</li>
<li>如果只有一个输入生命周期参数，那么它被赋予所有输出生命周期参数</li>
<li>如果方法有多个输入生命周期参数，不过其中之一因为方法的缘故为 <code>&amp;self</code> 或 <code>&amp;mut self</code>，那么 <code>self</code> 的生命周期被赋给所有输出生命周期参数</li>
</ul>
<h4 id="10-3-5-方法定义中的生命周期注解">10.3.5 方法定义中的生命周期注解</h4>
<p>（实现方法时）结构体字段的生命周期必须总是在 <code>impl</code> 关键字之后声明并在结构体名称之后被使用，因为这些生命周期是结构体类型的一部分。</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ImportantExcerpt</span></span>&lt;<span class="symbol">&#x27;a</span>&gt; &#123;</span><br><span class="line">    part: &amp;<span class="symbol">&#x27;a</span> <span class="built_in">str</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span>&lt;<span class="symbol">&#x27;a</span>&gt; ImportantExcerpt&lt;<span class="symbol">&#x27;a</span>&gt; &#123;</span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">announce_and_return_part</span></span>(&amp;<span class="keyword">self</span>, announcement: &amp;<span class="built_in">str</span>) -&gt; &amp;<span class="built_in">str</span> &#123;</span><br><span class="line">        <span class="built_in">println!</span>(<span class="string">&quot;Attention please: &#123;&#125;&quot;</span>, announcement);</span><br><span class="line">        <span class="keyword">self</span>.part</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="10-3-6-静态生命周期">10.3.6 静态生命周期</h4>
<ul>
<li>
<p><code>'static</code> 其生命周期<strong>能够</strong>存活于整个程序期间</p>
</li>
<li>
<p>所有的字符串字面值都拥有 <code>'static</code> 生命周期</p>
</li>
</ul>
<h2 id="Ch11-编写自动化测试">Ch11 编写自动化测试</h2>
<h3 id="11-1-如何编写测试">11.1 如何编写测试</h3>
<p>Rust 中的测试函数是用来验证非测试代码是否按照期望的方式运行的。测试函数体通常执行如下三种操作：</p>
<ol>
<li>设置任何所需的数据或状态</li>
<li>运行需要测试的代码</li>
<li>断言其结果是我们所期望的</li>
</ol>
<h4 id="11-1-1-测试函数剖析">11.1.1 测试函数剖析</h4>
<ul>
<li>为了将一个函数变成测试函数，需要在 <code>fn</code> 行之前加上 <code>#[test]</code></li>
<li>使用 <code>cargo test</code> 命令运行测试</li>
<li>使用 Cargo 新建一个<strong>库项目</strong>时，它会自动为我们生成一个测试模块和一个测试函数</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#[cfg(test)]</span></span><br><span class="line"><span class="keyword">mod</span> tests &#123;</span><br><span class="line">    <span class="meta">#[test]</span></span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">exploration</span></span>() &#123;</span><br><span class="line">        <span class="built_in">assert_eq!</span>(<span class="number">2</span> + <span class="number">2</span>, <span class="number">4</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="11-1-2-使用assert-宏来检查结果">11.1.2 使用assert!宏来检查结果</h4>
<ul>
<li>如果值是 <code>true</code>，<code>assert!</code> 什么也不做，同时测试会通过</li>
<li>如果值为 <code>false</code>，<code>assert!</code> 调用 <code>panic!</code> 宏，这会导致测试失败</li>
</ul>
<h4 id="11-1-3-使用assert-eq-和assert-ne-宏来测试相等">11.1.3 使用assert_eq!和assert_ne!宏来测试相等</h4>
<ul>
<li><code>assert_eq!</code> 判断是否相等，<code>assert_ne!</code> 判断是否不等</li>
<li>断言失败时他们会打印出这两个值具体是什么，以便于观察测试<strong>为什么</strong>失败</li>
</ul>
<h4 id="11-1-4-自定义失败信息">11.1.4 自定义失败信息</h4>
<p>为测试函数增加一个自定义失败信息参数：带占位符的格式字符串，以及 <code>greeting</code> 函数的值</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#[test]</span></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">greeting_contains_name</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> result = greeting(<span class="string">&quot;Carol&quot;</span>);</span><br><span class="line">    <span class="built_in">assert!</span>(</span><br><span class="line">        result.contains(<span class="string">&quot;Carol&quot;</span>),</span><br><span class="line">        <span class="string">&quot;Greeting did not contain name, value was `&#123;&#125;`&quot;</span>, result</span><br><span class="line">    );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="11-1-5-使用-should-panic-检查-panic">11.1.5 使用 should_panic 检查 panic</h4>
<ul>
<li><code>#[should_panic]</code> 属性位于 <code>#[test]</code> 之后，对应的测试函数之前</li>
<li>这个属性在函数中的代码 panic 时会通过，而在其中的代码没有 panic 时失败</li>
</ul>
<h4 id="11-1-6-将-Result-T-E-用于测试">11.1.6 将 Result&lt;T, E&gt; 用于测试</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#[cfg(test)]</span></span><br><span class="line"><span class="keyword">mod</span> tests &#123;</span><br><span class="line">    <span class="meta">#[test]</span></span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">it_works</span></span>() -&gt; <span class="built_in">Result</span>&lt;(), <span class="built_in">String</span>&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> <span class="number">2</span> + <span class="number">2</span> == <span class="number">4</span> &#123;</span><br><span class="line">            <span class="literal">Ok</span>(())</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="literal">Err</span>(<span class="built_in">String</span>::from(<span class="string">&quot;two plus two does not equal four&quot;</span>))</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="11-2-运行测试">11.2 运行测试</h3>
<h4 id="11-2-1-并行或连续的运行测试">11.2.1 并行或连续的运行测试</h4>
<ul>
<li>
<p>当运行多个测试时， Rust 默认使用线程来并行运行</p>
</li>
<li>
<p>应该确保测试不能相互依赖，或依赖任何共享的状态，包括依赖共享的环境</p>
</li>
<li>
<p>如果有依赖，可以限制线程：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo <span class="built_in">test</span> -- --test-threads=1</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="11-2-2-显示函数输出">11.2.2 显示函数输出</h4>
<ul>
<li>
<p>默认情况下，当测试通过时，Rust 的测试库会截获打印到标准输出的所有内容</p>
</li>
<li>
<p>如果你希望也能看到通过的测试中打印的值，截获输出的行为可以通过 <code>--nocapture</code> 参数来禁用：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo <span class="built_in">test</span> --nocapture</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="11-2-3-通过指定名字来运行部分测试">11.2.3 通过指定名字来运行部分测试</h4>
<ul>
<li>
<p>运行单个测试，向 <code>cargo test</code> 传递任意测试的名称来只运行这个测试</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo <span class="built_in">test</span> one_hundred</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>过滤运行多个测试，指定部分测试的名称，任何名称匹配这个名称的测试会被运行，以下命令运行了所有名字中带有 <code>add</code> 的测试</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo <span class="built_in">test</span> add</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="11-2-4-忽略某些测试">11.2.4 忽略某些测试</h4>
<p>使用 <code>ignore</code> 属性来标记耗时的测试并排除他们</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#[test]</span></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">it_works</span></span>() &#123;</span><br><span class="line">    <span class="built_in">assert_eq!</span>(<span class="number">2</span> + <span class="number">2</span>, <span class="number">4</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">#[test]</span></span><br><span class="line"><span class="meta">#[ignore]</span></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">expensive_test</span></span>() &#123;</span><br><span class="line">    <span class="comment">// 需要运行一个小时的代码</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>如果只希望运行被忽略的测试，可以使用 <code>cargo test -- --ignored</code></p>
<h3 id="11-3-测试的组织结构">11.3 测试的组织结构</h3>
<h4 id="11-3-1-单元测试">11.3.1 单元测试</h4>
<ul>
<li>单元测试的目的是在与其他部分隔离的环境中测试每一个单元的代码，以便于快速而准确的某个单元的代码功能是否符合预期。</li>
<li>单元测试与他们要测试的代码共同存放在位于 <em>src</em> 目录下相同的文件中。</li>
<li>规范是在每个文件中创建包含测试函数的 <code>tests</code> 模块，并使用 <code>cfg(test)</code> 标注模块。</li>
</ul>
<h5 id="测试模块">测试模块</h5>
<p>测试模块的 <code>#[cfg(test)]</code> 注解告诉 Rust 只在执行 <code>cargo test</code> 时才编译和运行测试代码</p>
<h4 id="11-3-2-集成测试">11.3.2 集成测试</h4>
<ul>
<li>
<p>集成测试的目的是测试库的多个部分能否一起正常工作</p>
</li>
<li>
<p>二进制项目，即只有 <em>src/main.rs</em> 而没有 <em>src/lib.rs</em> 不能进行集成测试</p>
</li>
<li>
<p>为了编写集成测试，需要在项目根目录创建一个 <em>tests</em> 目录，与 <em>src</em> 同级，可以随意在这个目录中创建任意多的测试文件</p>
</li>
<li>
<p>需要在文件顶部添加 <code>use</code></p>
</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> adder;</span><br><span class="line"></span><br><span class="line"><span class="meta">#[test]</span></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">it_adds_two</span></span>() &#123;</span><br><span class="line">    <span class="built_in">assert_eq!</span>(<span class="number">4</span>, adder::add_two(<span class="number">2</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Ch12-I-O项目：命令行程序">Ch12 I/O项目：命令行程序</h2>
<h3 id="12-1-接受命令行参数">12.1 接受命令行参数</h3>
<ul>
<li>使用标准库提供的函数：<code>std::env::args</code> ，返回一个传递给程序的命令行参数的<strong>迭代器</strong></li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::env;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> args: <span class="built_in">Vec</span>&lt;<span class="built_in">String</span>&gt; = env::args().collect();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> query = &amp;args[<span class="number">1</span>];</span><br><span class="line">    <span class="keyword">let</span> filename = &amp;args[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;Searching for &#123;&#125;&quot;</span>, query);</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;In file &#123;&#125;&quot;</span>, filename);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="12-2-读取文件">12.2 读取文件</h3>
<ul>
<li>使用标准库  <code>std::fs</code> 来处理文件</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> contents = fs::read_to_string(filename)</span><br><span class="line">        .expect(<span class="string">&quot;Something went wrong reading the file&quot;</span>);</span><br><span class="line"><span class="built_in">println!</span>(<span class="string">&quot;With text:\n&#123;&#125;&quot;</span>, contents);</span><br></pre></td></tr></table></figure>
<h3 id="12-3-重构改进模块性和错误处理">12.3 重构改进模块性和错误处理</h3>
<p>在 <code>main</code> 函数开始变得庞大时进行二进制程序的关注分离的指导性过程:</p>
<ul>
<li>将程序拆分成 <em><a target="_blank" rel="noopener" href="http://main.rs">main.rs</a></em> 和 <em><a target="_blank" rel="noopener" href="http://lib.rs">lib.rs</a></em> 并将程序的逻辑放入 <em><a target="_blank" rel="noopener" href="http://lib.rs">lib.rs</a></em> 中。</li>
<li>当命令行解析逻辑比较小时，可以保留在 <em><a target="_blank" rel="noopener" href="http://main.rs">main.rs</a></em> 中。</li>
<li>当命令行解析开始变得复杂时，也同样将其从 <em><a target="_blank" rel="noopener" href="http://main.rs">main.rs</a></em> 提取到 <em><a target="_blank" rel="noopener" href="http://lib.rs">lib.rs</a></em> 中。</li>
</ul>
<p>经过这些过程之后保留在 <code>main</code> 函数中的责任应该被限制为：</p>
<ul>
<li>使用参数值调用命令行解析逻辑</li>
<li>设置任何其他的配置</li>
<li>调用 <em><a target="_blank" rel="noopener" href="http://lib.rs">lib.rs</a></em> 中的 <code>run</code> 函数</li>
<li>如果 <code>run</code> 返回错误，则处理这个错误</li>
</ul>
<h3 id="12-4-采用测试驱动开发完善库的功能">12.4 采用测试驱动开发完善库的功能</h3>
<p>测试驱动开发（Test Driven Development, TDD）模式，是一个软件开发技术，它遵循如下步骤：</p>
<ol>
<li>编写一个会失败的测试，并运行它以确保其因为你期望的原因失败。</li>
<li>编写或修改刚好足够的代码来使得新的测试通过。</li>
<li>重构刚刚增加或修改的代码，并确保测试仍然能通过。</li>
<li>从步骤 1 开始重复！</li>
</ol>
<h3 id="12-6-将错误信息输出到标准错误">12.6 将错误信息输出到标准错误</h3>
<ul>
<li>
<p>使用 <code>eprintln!</code> 将错误信息写入标准错误而不是标准输出</p>
</li>
<li>
<p>使用输出重定向：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ cargo run to poem.txt &gt; output.txt</span><br></pre></td></tr></table></figure>
<ul>
<li>若出错，会输出到标准错误，即显示在命令行，而不写入 <em>output.txt</em></li>
<li>若正常执行，会输出到标准输出，即重定向到 <em>output.txt</em></li>
</ul>
</li>
</ul>
<h2 id="Ch13-迭代器和闭包">Ch13 迭代器和闭包</h2>
<h3 id="13-1-闭包">13.1 闭包</h3>
<ul>
<li>
<p>可以保存进变量或作为参数传递给其他函数的匿名函数</p>
</li>
<li>
<p>使用闭包的原因是我们需要在一个位置定义代码，储存代码，并在之后的位置实际调用它</p>
</li>
</ul>
<h4 id="13-1-1-定义闭包">13.1.1 定义闭包</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::thread;</span><br><span class="line"><span class="keyword">use</span> std::time::Duration;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> expensive_closure = |num| &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;calculating slowly...&quot;</span>);</span><br><span class="line">    thread::sleep(Duration::from_secs(<span class="number">2</span>));</span><br><span class="line">    num</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">expensive_closure(<span class="number">5</span>);</span><br></pre></td></tr></table></figure>
<ul>
<li>闭包的定义以一对竖线（<code>|</code>）开始，在竖线中指定闭包的参数</li>
<li>如果有多于一个参数，可以使用逗号分隔，比如 <code>|param1, param2|</code></li>
</ul>
<h4 id="13-1-2-闭包类型推断和注解">13.1.2 闭包类型推断和注解</h4>
<ul>
<li>闭包不用于暴露在外的接口：他们储存在变量中并被使用，不用命名他们或暴露给库的用户调用</li>
<li>闭包定义会为每个参数和返回值推断一个具体类型</li>
<li>如果尝试调用闭包两次，第一次使用 <code>String</code> 类型作为参数而第二次使用 <code>u32</code>，则会得到一个错误</li>
</ul>
<h4 id="13-1-3-使用带有泛型和Fn-trait的闭包">13.1.3 使用带有泛型和Fn trait的闭包</h4>
<p>可以创建一个存放闭包和调用闭包结果的结构体，该结构体只会在需要结果时执行闭包，并会缓存结果值，这样余下的代码就不必再负责保存结果并可以复用该值</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Cacher</span></span>&lt;T&gt;</span><br><span class="line">	<span class="comment">// 闭包有一个 u32 的参数并返回一个 u32</span></span><br><span class="line">    <span class="keyword">where</span> T: <span class="built_in">Fn</span>(<span class="built_in">u32</span>) -&gt; <span class="built_in">u32</span></span><br><span class="line">&#123;</span><br><span class="line">    calculation: T,</span><br><span class="line">    value: <span class="built_in">Option</span>&lt;<span class="built_in">u32</span>&gt;,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span>&lt;T&gt; Cacher&lt;T&gt;</span><br><span class="line">    <span class="keyword">where</span> T: <span class="built_in">Fn</span>(<span class="built_in">u32</span>) -&gt; <span class="built_in">u32</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">new</span></span>(calculation: T) -&gt; Cacher&lt;T&gt; &#123;</span><br><span class="line">        Cacher &#123;</span><br><span class="line">            calculation,</span><br><span class="line">            value: <span class="literal">None</span>,</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">value</span></span>(&amp;<span class="keyword">mut</span> <span class="keyword">self</span>, arg: <span class="built_in">u32</span>) -&gt; <span class="built_in">u32</span> &#123;</span><br><span class="line">        <span class="keyword">match</span> <span class="keyword">self</span>.value &#123;</span><br><span class="line">            <span class="comment">/*检查self.value是否已经有了一个 Some 的结果值；</span></span><br><span class="line"><span class="comment">            如果有，它返回 Some 中的值并不会再次执行闭包*/</span></span><br><span class="line">            <span class="literal">Some</span>(v) =&gt; v,</span><br><span class="line">            <span class="comment">/* 如果 self.value 是 None，</span></span><br><span class="line"><span class="comment">            则会调用 self.calculation 中储存的闭包，</span></span><br><span class="line"><span class="comment">            将结果保存到 self.value 以便将来使用，</span></span><br><span class="line"><span class="comment">            并同时返回结果值*/</span></span><br><span class="line">            <span class="literal">None</span> =&gt; &#123;</span><br><span class="line">                <span class="keyword">let</span> v = (<span class="keyword">self</span>.calculation)(arg);</span><br><span class="line">                <span class="keyword">self</span>.value = <span class="literal">Some</span>(v);</span><br><span class="line">                v</span><br><span class="line">            &#125;,</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在执行闭包之前，<code>value</code> 将是 <code>None</code>。如果使用 <code>Cacher</code> 的代码请求闭包的结果，这时会执行闭包并将结果储存在 <code>value</code> 字段的 <code>Some</code> 成员中。接着如果代码再次请求闭包的结果，这时不再执行闭包，而是会返回存放在 <code>Some</code> 成员中的结果。</p>
<ul>
<li><code>Cacher</code> 实现的限制：
<ul>
<li>第一次初始化 <code>value</code> 的值之后，就无法再改动；可以通过使 <code>Cacher</code> 存储一个哈希map而不是一个单独的值解决</li>
<li>它的应用被限制为只接受获取一个 <code>u32</code> 值并返回一个 <code>u32</code> 值的闭包</li>
</ul>
</li>
</ul>
<h4 id="13-1-4-闭包会捕获其环境">13.1.4 闭包会捕获其环境</h4>
<ul>
<li>
<p>闭包周围的作用域被称为其<strong>环境</strong></p>
</li>
<li>
<p>闭包可以捕获其环境并访问其被定义的作用域的变量</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> x = <span class="number">4</span>;</span><br><span class="line">	<span class="comment">/* x 并不是 equal_to_x 的一个参数，</span></span><br><span class="line"><span class="comment">	但equal_to_x 闭包也被允许使用变量 x，</span></span><br><span class="line"><span class="comment">	因为它与 equal_to_x 定义于相同的作用域*/</span></span><br><span class="line">    <span class="keyword">let</span> equal_to_x = |z| z == x;</span><br><span class="line">    <span class="keyword">let</span> y = <span class="number">4</span>;</span><br><span class="line">    <span class="built_in">assert!</span>(equal_to_x(y));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>闭包有三种方式捕获其环境</p>
<ul>
<li><code>FnOnce</code> 消费从周围作用域捕获的变量。为了消费捕获到的变量，闭包必须获取其所有权并在定义闭包时将其移动进闭包。其名称的 <code>Once</code> 部分代表了闭包不能多次获取相同变量的所有权的事实，所以它只能被调用一次</li>
<li><code>FnMut</code> 获取可变的借用值，所以可以改变其环境</li>
<li><code>Fn</code> 从其环境获取不可变的借用值</li>
</ul>
</li>
</ul>
<h3 id="13-2-迭代器">13.2 迭代器</h3>
<ul>
<li>
<p><strong>迭代器</strong>（<em>iterator</em>）负责遍历序列中的每一项和决定序列何时结束的逻辑</p>
</li>
<li>
<p>迭代器是惰性的，即在调用方法使用迭代器之前它都不会有效果</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> v1 = <span class="built_in">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="comment">// 创建一个迭代器，但是没有任何效果</span></span><br><span class="line"><span class="keyword">let</span> v1_iter = v1.iter();</span><br><span class="line"><span class="comment">/* 使用迭代器遍历，迭代器中的元素才开始迭代</span></span><br><span class="line"><span class="comment">用 for 循环时无需使 v1_iter 可变，</span></span><br><span class="line"><span class="comment">因为 for 循环会获取 v1_iter 的所有权并在后台使 v1_iter 可变*/</span></span><br><span class="line"><span class="keyword">for</span> val <span class="keyword">in</span> v1_iter &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;Got: &#123;&#125;&quot;</span>, val);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="13-2-1-Iterator-trait-和-next方法">13.2.1 Iterator trait 和 next方法</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Iterator 是定义于标准库的 trait</span></span><br><span class="line"><span class="keyword">pub</span> <span class="class"><span class="keyword">trait</span> <span class="title">Iterator</span></span> &#123;</span><br><span class="line">    <span class="comment">// Item类型将是迭代器next方法返回元素的类型</span></span><br><span class="line">    <span class="class"><span class="keyword">type</span> <span class="title">Item</span></span>;</span><br><span class="line">	<span class="comment">// next 一次返回迭代器中的一个项，封装在 Some 中，当迭代器结束时，它返回 None</span></span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">next</span></span>(&amp;<span class="keyword">mut</span> <span class="keyword">self</span>) -&gt; <span class="built_in">Option</span>&lt;Self::Item&gt;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 此处省略了方法的默认实现</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在迭代器上直接调用 <code>next</code> 方法</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#[test]</span></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">iterator_demonstration</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> v1 = <span class="built_in">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">	<span class="comment">// 需要将迭代器定义为可变，因为next方法会改变迭代器</span></span><br><span class="line">    <span class="keyword">let</span> <span class="keyword">mut</span> v1_iter = v1.iter();</span><br><span class="line"></span><br><span class="line">    <span class="built_in">assert_eq!</span>(v1_iter.next(), <span class="literal">Some</span>(&amp;<span class="number">1</span>));</span><br><span class="line">    <span class="built_in">assert_eq!</span>(v1_iter.next(), <span class="literal">Some</span>(&amp;<span class="number">2</span>));</span><br><span class="line">    <span class="built_in">assert_eq!</span>(v1_iter.next(), <span class="literal">Some</span>(&amp;<span class="number">3</span>));</span><br><span class="line">    <span class="built_in">assert_eq!</span>(v1_iter.next(), <span class="literal">None</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="13-2-2-消费适配器">13.2.2 消费适配器</h4>
<ul>
<li>
<p>调用 <code>next</code> 方法的方法，如 <code>sum</code></p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#[test]</span></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">iterator_sum</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> v1 = <span class="built_in">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line">    <span class="keyword">let</span> v1_iter = v1.iter();</span><br><span class="line">	<span class="comment">// 调用 sum 之后不再允许使用 v1_iter 因为调用 sum 时它会获取迭代器的所有权</span></span><br><span class="line">    <span class="keyword">let</span> total: <span class="built_in">i32</span> = v1_iter.sum();</span><br><span class="line"></span><br><span class="line">    <span class="built_in">assert_eq!</span>(total, <span class="number">6</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="13-2-3-迭代器适配器">13.2.3 迭代器适配器</h4>
<ul>
<li>
<p>将当前迭代器变为不同类型的迭代器，如 <code>map</code></p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> v1: <span class="built_in">Vec</span>&lt;<span class="built_in">i32</span>&gt; = <span class="built_in">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="comment">// 调用 map 方法创建一个新迭代器，接着调用collect方法消费新迭代器并创建一个vector</span></span><br><span class="line"><span class="keyword">let</span> v2: <span class="built_in">Vec</span>&lt;_&gt; = v1.iter().map(|x| x + <span class="number">1</span>).collect();</span><br><span class="line"><span class="built_in">assert_eq!</span>(v2, <span class="built_in">vec!</span>[<span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]);</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="13-2-4-创建自定义迭代器">13.2.4 创建自定义迭代器</h4>
<p>可以实现 <code>Iterator</code> trait 来创建任何我们希望的迭代器</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Counter</span></span> &#123;</span><br><span class="line">    count: <span class="built_in">u32</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span> Counter &#123;</span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">new</span></span>() -&gt; Counter &#123;</span><br><span class="line">        Counter &#123; count: <span class="number">0</span> &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span> <span class="built_in">Iterator</span> <span class="keyword">for</span> Counter &#123;</span><br><span class="line">    <span class="class"><span class="keyword">type</span> <span class="title">Item</span></span> = <span class="built_in">u32</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">next</span></span>(&amp;<span class="keyword">mut</span> <span class="keyword">self</span>) -&gt; <span class="built_in">Option</span>&lt;Self::Item&gt; &#123;</span><br><span class="line">        <span class="keyword">self</span>.count += <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">self</span>.count &lt; <span class="number">6</span> &#123;</span><br><span class="line">            <span class="literal">Some</span>(<span class="keyword">self</span>.count)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="literal">None</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用自定义的Counter迭代器的多种方法</span></span><br><span class="line"><span class="comment">// 获取 Counter 实例产生的值，将这些值与另一个 Counter 实例在省略了第一个值之后产生的值配对，将每一对值相乘，只保留那些可以被三整除的结果，然后将所有保留的结果相加</span></span><br><span class="line"><span class="meta">#[test]</span></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">using_other_iterator_trait_methods</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> sum: <span class="built_in">u32</span> = Counter::new().zip(Counter::new().skip(<span class="number">1</span>))</span><br><span class="line">                                 .map(|(a, b)| a * b)</span><br><span class="line">                                 .filter(|x| x % <span class="number">3</span> == <span class="number">0</span>)</span><br><span class="line">                                 .sum();</span><br><span class="line">    <span class="built_in">assert_eq!</span>(<span class="number">18</span>, sum);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Ch14-进一步认识Cargo和Crates-io">Ch14 <a target="_blank" rel="noopener" href="http://xn--CargoCrates-km8q749dp96e4c7etpa368c.io">进一步认识Cargo和Crates.io</a></h2>
<h3 id="14-1-采用发布配置自定义构建">14.1 采用发布配置自定义构建</h3>
<p>Cargo 有两个主要的配置：</p>
<ul>
<li>运行 <code>cargo build</code> 时采用的 <code>dev</code> 配置</li>
<li>运行 <code>cargo build --release</code> 的 <code>release</code> 配置</li>
</ul>
<p><code>dev</code> 配置被定义为开发时的好的默认配置，<code>release</code> 配置则有着良好的发布构建的默认配置</p>
<p>可以在 <em>Cargo.toml</em> 文件中定义 <code>[profile.*]</code> 部分来覆盖默认配置</p>
<figure class="highlight toml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[profile.dev]</span></span><br><span class="line"><span class="attr">opt-level</span> = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="section">[profile.release]</span></span><br><span class="line"><span class="attr">opt-level</span> = <span class="number">3</span></span><br></pre></td></tr></table></figure>
<ul>
<li><code>opt-level</code> 设置控制 Rust 会对代码进行何种程度的优化，值从0到3，越高的优化级别需要更多的时间编译</li>
</ul>
<h3 id="14-2-将-crate-发布到-Crates-io">14.2 将 crate 发布到 <a target="_blank" rel="noopener" href="http://Crates.io">Crates.io</a></h3>
<h3 id="14-3-Cargo工作空间">14.3 Cargo工作空间</h3>
<h3 id="14-4-从-Crates-io-安装二进制文件">14.4 从 <a target="_blank" rel="noopener" href="http://Crates.io">Crates.io</a> 安装二进制文件</h3>
<p>使用命令 <code>cargo install</code> 可以从crates.io下载二进制crate，安装到 <em>~/.cargo/bin</em></p>
<h2 id="Ch15-智能指针">Ch15 智能指针</h2>
<h3 id="15-1-Box-T">15.1 Box&lt;T&gt;</h3>
<p>box 允许将一个值放在堆上而不是栈上，留在栈上的则是指向堆数据的指针</p>
<p>使用场景：</p>
<ul>
<li>当有一个在编译时未知大小的类型，而又想要在需要确切大小的上下文中使用这个类型值的时候</li>
<li>当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候</li>
<li>当希望拥有一个值并只关心它的类型是否实现了特定 trait 而不是其具体类型的时候</li>
</ul>
<h4 id="15-1-1-Box创建递归类型">15.1.1 Box创建递归类型</h4>
<ul>
<li>Rust 需要在编译时知道类型占用多少空间，而<strong>递归类型</strong>无法在编译的时候知道大小</li>
<li>box 有一个已知的大小，所以通过在循环类型定义中插入 box，就可以创建递归类型了</li>
</ul>
<h5 id="以cons-list为例">以cons list为例</h5>
<ul>
<li>
<p>cons list 的每一项都包含两个元素：当前项的值和下一项。</p>
</li>
<li>
<p>其最后一项值包含一个叫做 <code>Nil</code> 的值且没有下一项。</p>
</li>
<li>
<p>cons list 通过递归调用 <code>cons</code> 函数产生。</p>
</li>
<li>
<p>代表递归的终止条件（base case）的规范名称是 <code>Nil</code>，它宣布列表的终止。</p>
</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">List</span></span> &#123;</span><br><span class="line">    Cons(<span class="built_in">i32</span>, List),</span><br><span class="line">    Nil,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> crate::List::&#123;Cons, Nil&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> list = Cons(<span class="number">1</span>, Cons(<span class="number">2</span>, Cons(<span class="number">3</span>, Nil)));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Rust编译器无法计算一个 <code>List</code> 需要的大小，因为编译器尝试计算出储存一个 <code>List</code> 枚举需要多少内存，并开始检查 <code>Cons</code> 成员，那么 <code>Cons</code> 需要的空间等于 <code>i32</code> 的大小加上 <code>List</code> 的大小。为了计算 <code>List</code> 需要多少内存，它检查其成员，从 <code>Cons</code> 成员开始。<code>Cons</code>成员储存了一个 <code>i32</code> 值和一个<code>List</code>值，这样的计算将无限进行下去。</p>
<h5 id="使用Box-T-给递归类型一个已知的大小">使用Box&lt;T&gt;给递归类型一个已知的大小</h5>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">List</span></span> &#123;</span><br><span class="line">    Cons(<span class="built_in">i32</span>, <span class="built_in">Box</span>&lt;List&gt;),</span><br><span class="line">    Nil,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> crate::List::&#123;Cons, Nil&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> list = Cons(<span class="number">1</span>,</span><br><span class="line">        <span class="built_in">Box</span>::new(Cons(<span class="number">2</span>,</span><br><span class="line">            <span class="built_in">Box</span>::new(Cons(<span class="number">3</span>,</span><br><span class="line">                <span class="built_in">Box</span>::new(Nil))))));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>任何 <code>List</code> 值最多需要一个 <code>i32</code> 加上 box 指针数据的大小。通过使用 box ，打破了这无限递归的连锁，这样编译器就能够计算出储存 <code>List</code> 值需要的大小了。</p>
<h3 id="15-2-Deref-trait">15.2 Deref trait</h3>
<p>实现 <code>Deref</code> trait 允许我们重载<strong>解引用运算符</strong> <code>*</code></p>
<h4 id="15-2-1-像引用一样使用-Box-T">15.2.1 像引用一样使用 Box&lt;T&gt;</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> x = <span class="number">5</span>;</span><br><span class="line">    <span class="keyword">let</span> y = <span class="built_in">Box</span>::new(x);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">assert_eq!</span>(<span class="number">5</span>, x);</span><br><span class="line">    <span class="built_in">assert_eq!</span>(<span class="number">5</span>, *y);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="15-2-2-自定义智能指针">15.2.2 自定义智能指针</h4>
<p>定义 <code>MyBox&lt;T&gt;</code> 类型:</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">MyBox</span></span>&lt;T&gt;(T);</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span>&lt;T&gt; MyBox&lt;T&gt; &#123;</span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">new</span></span>(x: T) -&gt; MyBox&lt;T&gt; &#123;</span><br><span class="line">        MyBox(x)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="15-2-3-在自定义智能指针实现-Deref-trait">15.2.3 在自定义智能指针实现 Deref trait</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::ops::Deref;</span><br><span class="line"></span><br><span class="line"><span class="keyword">impl</span>&lt;T&gt; Deref <span class="keyword">for</span> MyBox&lt;T&gt; &#123;</span><br><span class="line">    <span class="comment">// 定义trait的关联类型</span></span><br><span class="line">    <span class="class"><span class="keyword">type</span> <span class="title">Target</span></span> = T;</span><br><span class="line">    <span class="function"><span class="keyword">fn</span> <span class="title">deref</span></span>(&amp;<span class="keyword">self</span>) -&gt; &amp;T &#123;</span><br><span class="line">        <span class="comment">// deref返回了我希望通过*运算符访问的值的引用</span></span><br><span class="line">        &amp;<span class="keyword">self</span>.<span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>当运行如下代码：</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> x = <span class="number">5</span>;</span><br><span class="line"><span class="keyword">let</span> y = MyBox::new(x);</span><br><span class="line"></span><br><span class="line"><span class="built_in">assert_eq!</span>(<span class="number">5</span>, *y);</span><br></pre></td></tr></table></figure>
<p><code>*y</code> 在Rust底层运行了 <code>*(y.deref())</code></p>
<h4 id="15-2-4-函数和方法的隐式解引用强制多态">15.2.4 函数和方法的隐式解引用强制多态</h4>
<p><strong>解引用强制多态</strong>是 Rust 在函数或方法传参上的一种便利。将实现了 <code>Deref</code> 的类型的引用转换为原始类型通过 <code>Deref</code> 所能够转换的类型的引用。</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">hello</span></span>(name: &amp;<span class="built_in">str</span>) &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;Hello, &#123;&#125;!&quot;</span>, name);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> m = MyBox::new(<span class="built_in">String</span>::from(<span class="string">&quot;Rust&quot;</span>));</span><br><span class="line">    <span class="comment">// 解引用强制多态将 &amp;MyBox&lt;String&gt; 自动转换为 &amp;str</span></span><br><span class="line">    hello(&amp;m);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="15-3-Drop-trait">15.3 Drop trait</h3>
<ul>
<li>
<p>允许我们在值要离开作用域时执行一些代码，可以为任何类型提供 <code>Drop</code> trait 的实现，同时所指定的代码被用于释放类似于文件或网络连接的资源</p>
</li>
<li>
<p>通过 <code>Drop</code> trait 中的 <code>drop</code> 方法，可以在变量离开作用域时自动丢弃该值</p>
</li>
</ul>
<h4 id="15-3-1-通过-std-mem-drop-提早丢弃值">15.3.1 通过 std::mem::drop 提早丢弃值</h4>
<ul>
<li>Rust不允许我们主动调用 <code>Drop</code> trait 的 <code>drop</code> 方法</li>
<li>当我们希望在作用域结束之前就强制释放变量的话，我们应该使用的是由标准库提供的 <code>std::mem::drop</code>，其位于preclude，可以直接通过 <code>drop(variable);</code> 调用</li>
</ul>
<h3 id="15-4-Rc-T-引用计数智能指针">15.4 Rc&lt;T&gt; 引用计数智能指针</h3>
<ul>
<li>
<p>有些情况单个值可能会有多个所有者。例如，在图数据结构中，多个边可能指向相同的结点，而这个结点从概念上讲为所有指向它的边所拥有。结点直到没有任何边指向它之前都不应该被清理。</p>
</li>
<li>
<p>Rust 使用<strong>引用计数</strong> <code>Rc&lt;T&gt;</code> 的类型来启用多所有权，记录了一个值引用的数量来知晓这个值是否仍在被使用。</p>
</li>
<li>
<p><code>Rc&lt;T&gt;</code> 用于当我们希望在堆上分配一些内存供程序的多个部分读取，而且无法在编译时确定程序的哪一部分会最后结束使用它的时候。</p>
</li>
<li>
<p><code>Rc&lt;T&gt;</code> 只能用于单线程场景</p>
</li>
</ul>
<h4 id="15-4-1-使用-Rc-T-共享数据">15.4.1 使用 Rc&lt;T&gt; 共享数据</h4>
<p>使用 <code>Box&lt;T&gt;</code> 定义的 cons list 的两个列表 <code>b</code> 和 <code>c</code>, 共享第三个列表 <code>a</code> 的所有权</p>
<p><img src="https://cdn.jsdelivr.net/gh/Schenk75/Source@master/notes/Rust-notes/image-20201112210915469.png" class="lazyload" data-srcset="https://cdn.jsdelivr.net/gh/Schenk75/Source@master/notes/Rust-notes/image-20201112210915469.png" srcset="" alt="image-20201112210915469"></p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">List</span></span> &#123;</span><br><span class="line">    Cons(<span class="built_in">i32</span>, Rc&lt;List&gt;),</span><br><span class="line">    Nil,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> crate::List::&#123;Cons, Nil&#125;;</span><br><span class="line"><span class="keyword">use</span> std::rc::Rc;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> a = Rc::new(Cons(<span class="number">5</span>, Rc::new(Cons(<span class="number">10</span>, Rc::new(Nil)))));</span><br><span class="line">    <span class="keyword">let</span> b = Cons(<span class="number">3</span>, Rc::clone(&amp;a));</span><br><span class="line">    <span class="keyword">let</span> c = Cons(<span class="number">4</span>, Rc::clone(&amp;a));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li><code>Rc::clone</code> 只会增加引用计数，而不会深拷贝</li>
<li>在程序中每个引用计数变化的点，会打印出引用计数，其值可以通过调用 <code>Rc::strong_count</code> 函数获得</li>
</ul>
<h3 id="15-5-RefCell-T-和内部可变性模式">15.5 RefCell&lt;T&gt; 和内部可变性模式</h3>
<p><strong>内部可变性</strong>是 Rust 中的一个设计模式，它允许你即使在有不可变引用时也可以改变数据，这通常是借用规则所不允许的</p>
<h3 id="15-6-引用循环与内存泄漏">15.6 引用循环与内存泄漏</h3>
<p>Rust 的内存安全性保证使其难以意外地制造永远也不会被清理的内存，但是创建引用循环从而造成内存泄漏的可能性是存在的</p>
<h2 id="Ch16-并发">Ch16 并发</h2>
<h3 id="16-1-使用线程同时运行代码">16.1 使用线程同时运行代码</h3>
<p>线程是同时运行的，所以无法预先保证不同线程中的代码的执行顺序。这会导致诸如此类的问题：</p>
<ul>
<li>竞争状态，多个线程以不一致的顺序访问数据或资源</li>
<li>死锁，两个线程相互等待对方停止使用其所拥有的资源，这会阻止它们继续运行</li>
<li>只会发生在特定情况且难以稳定重现和修复的 bug</li>
</ul>
<h4 id="16-1-1-使用-spawn-创建新线程">16.1.1 使用 spawn 创建新线程</h4>
<p>为了创建一个新线程，需要调用 <code>thread::spawn</code> 函数并传递一个闭包，并在其中包含希望在新线程运行的代码</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::thread;</span><br><span class="line"><span class="keyword">use</span> std::time::Duration;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    thread::spawn(|| &#123;</span><br><span class="line">        <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>..<span class="number">10</span> &#123;</span><br><span class="line">            <span class="built_in">println!</span>(<span class="string">&quot;hi number &#123;&#125; from the spawned thread!&quot;</span>, i);</span><br><span class="line">            <span class="comment">// thread::sleep调用强制线程停止执行一小段时间，允许其他不同的线程运行</span></span><br><span class="line">            thread::sleep(Duration::from_millis(<span class="number">1</span>));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>..<span class="number">5</span> &#123;</span><br><span class="line">        <span class="built_in">println!</span>(<span class="string">&quot;hi number &#123;&#125; from the main thread!&quot;</span>, i);</span><br><span class="line">        thread::sleep(Duration::from_millis(<span class="number">1</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">输出：</span></span><br><span class="line"><span class="comment">hi number 1 from the main thread!</span></span><br><span class="line"><span class="comment">hi number 1 from the spawned thread!</span></span><br><span class="line"><span class="comment">hi number 2 from the main thread!</span></span><br><span class="line"><span class="comment">hi number 2 from the spawned thread!</span></span><br><span class="line"><span class="comment">hi number 3 from the main thread!</span></span><br><span class="line"><span class="comment">hi number 3 from the spawned thread!</span></span><br><span class="line"><span class="comment">hi number 4 from the main thread!</span></span><br><span class="line"><span class="comment">hi number 4 from the spawned thread!</span></span><br><span class="line"><span class="comment">hi number 5 from the spawned thread!</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>
<ul>
<li>当主线程结束时，新线程也会结束，而不管其是否执行完毕</li>
</ul>
<h4 id="16-1-2-使用-join-等待所有线程结束">16.1.2 使用 join 等待所有线程结束</h4>
<ul>
<li><code>thread::spawn</code> 的返回值类型是 <code>JoinHandle</code></li>
<li><code>JoinHandle</code> 是一个拥有所有权的值，当对其调用 <code>join</code> 方法时，它会等待其线程结束</li>
<li>通过调用 handle 的 join 会阻塞当前线程直到 handle 所代表的线程结束</li>
</ul>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::thread;</span><br><span class="line"><span class="keyword">use</span> std::time::Duration;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="comment">// 从thread::spawn保存一个JoinHandle来确保该线程能够运行结束</span></span><br><span class="line">    <span class="keyword">let</span> handle = thread::spawn(|| &#123;</span><br><span class="line">        <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>..<span class="number">10</span> &#123;</span><br><span class="line">            <span class="built_in">println!</span>(<span class="string">&quot;hi number &#123;&#125; from the spawned thread!&quot;</span>, i);</span><br><span class="line">            thread::sleep(Duration::from_millis(<span class="number">1</span>));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">1</span>..<span class="number">5</span> &#123;</span><br><span class="line">        <span class="built_in">println!</span>(<span class="string">&quot;hi number &#123;&#125; from the main thread!&quot;</span>, i);</span><br><span class="line">        thread::sleep(Duration::from_millis(<span class="number">1</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    handle.join().unwrap();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="16-1-3-线程与-move-闭包">16.1.3 线程与 move 闭包</h4>
<p>在参数列表前使用 <code>move</code> 关键字强制闭包获取其使用的环境值的所有权，可用于创建新线程时将值的所有权从一个线程移动到另一个线程</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::thread;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> v = <span class="built_in">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> handle = thread::spawn(<span class="keyword">move</span> || &#123;</span><br><span class="line">        <span class="built_in">println!</span>(<span class="string">&quot;Here&#x27;s a vector: &#123;:?&#125;&quot;</span>, v);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    handle.join().unwrap();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="16-2-线程间消息传递">16.2 线程间消息传递</h3>
<p>Rust 中一个实现消息传递并发的主要工具是<strong>通道</strong></p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::thread;</span><br><span class="line"><span class="keyword">use</span> std::sync::mpsc;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> (tx, rx) = mpsc::channel();</span><br><span class="line"></span><br><span class="line">    thread::spawn(<span class="keyword">move</span> || &#123;</span><br><span class="line">        <span class="keyword">let</span> val = <span class="built_in">String</span>::from(<span class="string">&quot;hi&quot;</span>);</span><br><span class="line">        tx.send(val).unwrap();</span><br><span class="line">    &#125;);</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">let</span> received = rx.recv().unwrap();</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;Got: &#123;&#125;&quot;</span>, received);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>
<p>使用 <code>mpsc::channel</code> 函数创建一个新的通道，可以有多个<strong>发送端</strong>，但只能有一个<strong>接收端</strong>， <code>mpsc::channel</code> 函数返回一个元组：(发送端，接收端)，或 <code>(tx, rx)</code></p>
</li>
<li>
<p>通道的发送端有一个 <code>send</code> 方法用来获取需要放入通道的值，返回一个 <code>Result&lt;T, E&gt;</code> 类型</p>
<ul>
<li><code>send</code> 函数获取其参数的所有权并移动这个值归接收者所有，所以线程在发送 <code>val</code> 之后就不能再使用它了</li>
</ul>
</li>
<li>
<p>通道的接收端有两个有用的方法：<code>recv</code> 和 <code>try_recv</code></p>
<ul>
<li><code>recv</code> 会阻塞主线程执行直到从通道中接收一个值，一旦发送了一个值，<code>recv</code> 会在一个 <code>Result&lt;T, E&gt;</code> 中返回它；当通道发送端关闭，<code>recv</code> 会返回一个错误表明不会再有新的值到来了</li>
<li><code>try_recv</code> 不会阻塞，立刻返回一个 <code>Result&lt;T, E&gt;</code>：<code>Ok</code> 值包含可用的信息，而 <code>Err</code> 值代表此时没有任何消息</li>
</ul>
</li>
<li>
<p>可以将 <code>rx</code> 作为迭代器来接收发送端发送的多个数据，并通过 <code>for</code> 循环打印</p>
</li>
<li>
<p>可以通过 <code>clone</code> 方法来创建多个发送端:</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> (tx, rx) = mpsc::channel();</span><br><span class="line"><span class="keyword">let</span> tx1 = mpsc::Sender::clone(&amp;tx);</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="16-3-共享状态并发">16.3 共享状态并发</h3>
<h4 id="16-3-1-互斥器">16.3.1 互斥器</h4>
<ul>
<li>通过<strong>锁</strong>来保证任意时刻只有一个线程能访问某些数据</li>
<li>使用方式：
<ul>
<li>在使用数据之前尝试获取锁。</li>
<li>处理完被互斥器所保护的数据之后，必须解锁数据，这样其他线程才能够获取锁。</li>
</ul>
</li>
<li>使用 <code>Mutex&lt;T&gt;</code> 实现
<ul>
<li>通过关联函数 <code>new</code> 来创建 <code>Mutex&lt;T&gt;</code></li>
<li>使用 <code>lock</code> 方法获取锁，该方法会阻塞当前线程，直到拥有锁为止</li>
<li><code>lock</code> 调用返回一个叫做 <code>MutexGuard</code> 的智能指针，当其离开作用域时，会自动释放锁</li>
</ul>
</li>
</ul>
<h4 id="16-3-2-在线程间共享-Mutex-T">16.3.2 在线程间共享 Mutex&lt;T&gt;</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> std::sync::&#123;Mutex, Arc&#125;;</span><br><span class="line"><span class="keyword">use</span> std::thread;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> counter = Arc::new(Mutex::new(<span class="number">0</span>));</span><br><span class="line">    <span class="keyword">let</span> <span class="keyword">mut</span> handles = <span class="built_in">vec!</span>[];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> _ <span class="keyword">in</span> <span class="number">0</span>..<span class="number">10</span> &#123;</span><br><span class="line">        <span class="keyword">let</span> counter = Arc::clone(&amp;counter);</span><br><span class="line">        <span class="keyword">let</span> handle = thread::spawn(<span class="keyword">move</span> || &#123;</span><br><span class="line">            <span class="keyword">let</span> <span class="keyword">mut</span> num = counter.lock().unwrap();</span><br><span class="line">            *num += <span class="number">1</span>;</span><br><span class="line">        &#125;);</span><br><span class="line">        handles.push(handle);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> handle <span class="keyword">in</span> handles &#123;</span><br><span class="line">        handle.join().unwrap();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;Result: &#123;&#125;&quot;</span>, *counter.lock().unwrap());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>使用<strong>原子引用计数</strong> <code>Arc&lt;T&gt;</code> 来实现 <code>Mutex&lt;T&gt;</code> 在多线程之间共享所有权</li>
</ul>
<h2 id="Ch17-Rust面向对象">Ch17 Rust面向对象</h2>
<h3 id="17-1-面向对象语言的特征">17.1 面向对象语言的特征</h3>
<ul>
<li>对象包含数据和行为：结构体和枚举包含数据，<code>impl</code> 块提供对应方法</li>
<li>封装隐藏了实现细节：不添加 <code>pub</code> 就是私有的</li>
<li>通过继承重用代码：使用 <code>trait</code> 对象</li>
</ul>
<h3 id="17-2-为使用不同类型的值而设计的-trait-对象">17.2 为使用不同类型的值而设计的 trait 对象</h3>
<h3 id="17-3-面向对象设计模式的实现">17.3 面向对象设计模式的实现</h3>
<h2 id="Ch18-模式">Ch18 模式</h2>
<h3 id="18-1-用到模式的位置">18.1 用到模式的位置</h3>
<h4 id="18-1-1-match分支">18.1.1 match分支</h4>
<p>在形式上 <code>match</code> 表达式由 <code>match</code> 关键字、用于匹配的值和一个或多个分支构成，这些分支包含一个模式和在值匹配分支的模式时运行的表达式</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">match</span> VALUE &#123;</span><br><span class="line">    PATTERN =&gt; EXPRESSION,</span><br><span class="line">    PATTERN =&gt; EXPRESSION,</span><br><span class="line">    PATTERN =&gt; EXPRESSION,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="18-1-2-if-let-表达式">18.1.2 if let 表达式</h4>
<ul>
<li>等同于只关心一个情况的 <code>match</code> 语句简写</li>
<li><code>if let</code> 表达式的缺点在于其穷尽性没有为编译器所检查，而 <code>match</code> 表达式则检查了</li>
</ul>
<h4 id="18-1-3-while-let-条件循环">18.1.3 while let 条件循环</h4>
<p>允许只要模式匹配就一直进行 <code>while</code> 循环</p>
<h4 id="18-1-4-for循环">18.1.4 for循环</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (index, value) <span class="keyword">in</span> v.iter().enumerate() &#123;&#125;</span><br></pre></td></tr></table></figure>
<p>使用 <code>(index, value)</code> 来匹配 <code>enumerate</code></p>
<h4 id="18-1-5-let语句">18.1.5 let语句</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> PATTERN = EXPRESSION;</span><br></pre></td></tr></table></figure>
<h4 id="18-1-6-函数参数">18.1.6 函数参数</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">foo</span></span>(x: <span class="built_in">i32</span>) &#123;</span><br><span class="line">    <span class="comment">// 代码</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><code>x</code> 部分就是一个模式</p>
<h3 id="18-2-可反驳和不可反驳">18.2 可反驳和不可反驳</h3>
<ul>
<li>
<p>能匹配任何传递的可能值的模式被称为是<strong>不可反驳的</strong>，如 <code>let x = 5;</code> 中的 <code>x</code></p>
</li>
<li>
<p>对某些可能的值进行匹配会失败的模式被称为是<strong>可反驳的</strong>，如 <code>if let Some(x) = a_value</code> 中的 <code>Some(x)</code></p>
</li>
<li>
<p>函数参数、 <code>let</code> 语句和 <code>for</code> 循环只能接受不可反驳的模式</p>
</li>
<li>
<p>匹配分支必须使用可反驳模式，如 <code>if let</code></p>
</li>
</ul>
<h3 id="18-3-模式语法">18.3 模式语法</h3>
<h4 id="18-3-1-匹配字面值">18.3.1 匹配字面值</h4>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> x = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">match</span> x &#123;</span><br><span class="line">    <span class="number">1</span> =&gt; <span class="built_in">println!</span>(<span class="string">&quot;one&quot;</span>),</span><br><span class="line">    <span class="number">2</span> =&gt; <span class="built_in">println!</span>(<span class="string">&quot;two&quot;</span>),</span><br><span class="line">    <span class="number">3</span> =&gt; <span class="built_in">println!</span>(<span class="string">&quot;three&quot;</span>),</span><br><span class="line">    _ =&gt; <span class="built_in">println!</span>(<span class="string">&quot;anything&quot;</span>),</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="18-3-2-匹配命名变量">18.3.2 匹配命名变量</h4>
<p>命名变量是匹配任何值的不可反驳模式，当其用于 <code>match</code> 表达式时，情况会不一样</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> x = <span class="literal">Some</span>(<span class="number">5</span>);</span><br><span class="line">    <span class="keyword">let</span> y = <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">match</span> x &#123;</span><br><span class="line">        <span class="literal">Some</span>(<span class="number">50</span>) =&gt; <span class="built_in">println!</span>(<span class="string">&quot;Got 50&quot;</span>),</span><br><span class="line">        <span class="literal">Some</span>(y) =&gt; <span class="built_in">println!</span>(<span class="string">&quot;Matched, y = &#123;:?&#125;&quot;</span>, y),</span><br><span class="line">        _ =&gt; <span class="built_in">println!</span>(<span class="string">&quot;Default case, x = &#123;:?&#125;&quot;</span>, x),</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;at the end: x = &#123;:?&#125;, y = &#123;:?&#125;&quot;</span>, x, y);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">会打印：</span></span><br><span class="line"><span class="comment">Matched, y = 5</span></span><br><span class="line"><span class="comment">at the end: x = Some(5), y = 10</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>
<ul>
<li>在 <code>match</code> 表达式的新作用域中， <code>y</code> 是一个新变量，而不是开头声明为值 10 的那个 <code>y</code> ，新的 <code>y</code> 绑定会匹配任何 <code>Some</code> 中的值，在这里是 <code>x</code> 中的值</li>
</ul>
<h4 id="18-3-3-多个模式">18.3.3 多个模式</h4>
<p>使用 <code>|</code> 语法匹配多个模式</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> x = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">match</span> x &#123;</span><br><span class="line">    <span class="number">1</span> | <span class="number">2</span> =&gt; <span class="built_in">println!</span>(<span class="string">&quot;one or two&quot;</span>),</span><br><span class="line">    <span class="number">3</span> =&gt; <span class="built_in">println!</span>(<span class="string">&quot;three&quot;</span>),</span><br><span class="line">    _ =&gt; <span class="built_in">println!</span>(<span class="string">&quot;anything&quot;</span>),</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="18-3-4-通过-…-匹配值的范围">18.3.4 通过 …= 匹配值的范围</h4>
<ul>
<li>
<p>使用 <code>1..=5</code> 替代 <code>1 | 2 | 3 | 4 | 5</code></p>
</li>
<li>
<p>对 <code>char</code> 类型也适用：<code>'a'..='j'</code></p>
</li>
</ul>
<h4 id="18-3-5-忽略模式中的值">18.3.5 忽略模式中的值</h4>
<ul>
<li>
<p>使用 <code>_</code> 忽略整个值</p>
</li>
<li>
<p>通过 <code>_x</code> 来忽略未使用的变量</p>
</li>
<li>
<p>使用 <code>..</code> 忽略剩余的值</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">fn</span> <span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> numbers = (<span class="number">2</span>, <span class="number">4</span>, <span class="number">8</span>, <span class="number">16</span>, <span class="number">32</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">match</span> numbers &#123;</span><br><span class="line">        (first, .., last) =&gt; &#123;</span><br><span class="line">            <span class="built_in">println!</span>(<span class="string">&quot;Some numbers: &#123;&#125;, &#123;&#125;&quot;</span>, first, last);</span><br><span class="line">        &#125;,</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="18-3-6-匹配守卫">18.3.6 匹配守卫</h4>
<p><strong>匹配守卫</strong>（<em>match guard</em>）是一个指定于 <code>match</code> 分支模式之后的额外 <code>if</code> 条件，它也必须被满足才能选择此分支</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> num = <span class="literal">Some</span>(<span class="number">4</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">match</span> num &#123;</span><br><span class="line">    <span class="literal">Some</span>(x) <span class="keyword">if</span> x &lt; <span class="number">5</span> =&gt; <span class="built_in">println!</span>(<span class="string">&quot;less than five: &#123;&#125;&quot;</span>, x),</span><br><span class="line">    <span class="literal">Some</span>(x) =&gt; <span class="built_in">println!</span>(<span class="string">&quot;&#123;&#125;&quot;</span>, x),</span><br><span class="line">    <span class="literal">None</span> =&gt; (),</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="18-3-7-绑定">18.3.7 @绑定</h4>
<ul>
<li>
<p><code>@</code> 允许我们在创建一个存放值的变量的同时测试其值是否匹配模式</p>
</li>
<li>
<p>使用 <code>@</code> 可以在一个模式中同时测试和保存变量值</p>
<figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">Message</span></span> &#123;</span><br><span class="line">    Hello &#123; id: <span class="built_in">i32</span> &#125;,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> msg = Message::Hello &#123; id: <span class="number">5</span> &#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">match</span> msg &#123;</span><br><span class="line">    <span class="comment">// 将id值保存在id_variable中</span></span><br><span class="line">    Message::Hello &#123; id: id_variable @ <span class="number">3</span>..=<span class="number">7</span> &#125; =&gt; &#123;</span><br><span class="line">        <span class="built_in">println!</span>(<span class="string">&quot;Found an id in range: &#123;&#125;&quot;</span>, id_variable)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">// 无法保存id值</span></span><br><span class="line">    Message::Hello &#123; id: <span class="number">10</span>..=<span class="number">12</span> &#125; =&gt; &#123;</span><br><span class="line">        <span class="built_in">println!</span>(<span class="string">&quot;Found an id in another range&quot;</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    Message::Hello &#123; id &#125; =&gt; &#123;</span><br><span class="line">        <span class="built_in">println!</span>(<span class="string">&quot;Found some other id: &#123;&#125;&quot;</span>, id)</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="Ch19-高级特征">Ch19 高级特征</h2>
<h3 id="19-1-不安全的Rust">19.1 不安全的Rust</h3>
<h3 id="19-2-高级trait">19.2 高级trait</h3>
<h3 id="19-3-高级类型">19.3 高级类型</h3>
<h3 id="19-4-高级函数与闭包">19.4 高级函数与闭包</h3>
<h3 id="19-5-宏">19.5 宏</h3>

  
  
    
    <div class='footer'>
      
      
      
      
    </div>
  
  
    


  <div class='article-meta' id="bottom">
    <div class='new-meta-box'>
      
        
          <div class="new-meta-item date">
  <a class='notlink'>
    <i class="fas fa-calendar-alt fa-fw" aria-hidden="true"></i>
    <p>发布于：2020年11月16日</p>
  </a>
</div>

        
      
        
          
  
  <div class="new-meta-item meta-tags"><a class="tag" href="/tags/rust/" rel="nofollow"><i class="fas fa-hashtag fa-fw" aria-hidden="true"></i><p>rust</p></a></div>


        
      
    </div>
  </div>


  
  

  
    <div class="prev-next">
      
        <a class='prev' href='/2020/11/23/instruction/ubuntu-show-application/'>
          <p class='title'><i class="fas fa-chevron-left" aria-hidden="true"></i>Ubuntu将安装的应用固定到桌面</p>
          <p class='content'>升级了一下ubuntu，从18.04升到了20.04，发现自动安装了国际版的firefox，之前安装的国内版firefox目录还在/opt下，但是桌面显示的firefox是国际版的，且启动栏也没...</p>
        </a>
      
      
        <a class='next' href='/2020/11/11/learning-notes/C%E5%92%8C%E6%8C%87%E9%92%88notes/'>
          <p class='title'>Pointers on C - Learn<i class="fas fa-chevron-right" aria-hidden="true"></i></p>
          <p class='content'>Ch2 基本概念
2.1 环境
2.1.1 翻译环境


翻译过程：各源文件通过编译过程分别转为目标代码 -&gt; 各目标代码文件由链接器捆绑为单一完整的可执行程序


编译过程：预处理器处理...</p>
        </a>
      
    </div>
  
</article>


  

  






</div>
<aside class='l_side'>
  
  
    
    



  <section class="widget toc-wrapper shadow floatable desktop mobile" id="toc-div" >
    
  <header>
    
      <i class="fas fa-list fa-fw" aria-hidden="true"></i><span class='name'>本文目录</span>
    
  </header>


    <div class='content'>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch0-%E5%AE%89%E8%A3%85Rust"><span class="toc-text">Ch0 安装Rust</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch1-Cargo"><span class="toc-text">Ch1 Cargo</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-1-%E4%BD%BF%E7%94%A8Cargo%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE"><span class="toc-text">1.1 使用Cargo创建项目</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-1-1-Cargo-toml"><span class="toc-text">1.1.1 Cargo.toml</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-1-2-%E6%BA%90%E4%BB%A3%E7%A0%81%E7%9B%AE%E5%BD%95src"><span class="toc-text">1.1.2 源代码目录src</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-%E6%9E%84%E5%BB%BA%E5%B9%B6%E8%BF%90%E8%A1%8CCargo%E9%A1%B9%E7%9B%AE"><span class="toc-text">1.2 构建并运行Cargo项目</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-2-1-%E5%8F%AF%E6%89%A7%E8%A1%8C%E6%96%87%E4%BB%B6"><span class="toc-text">1.2.1 可执行文件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-2-2-Cargo-lock"><span class="toc-text">1.2.2 Cargo.lock</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-3-%E5%8F%91%E5%B8%83-release-%E6%9E%84%E5%BB%BA"><span class="toc-text">1.3 发布(release)构建</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch2-%E5%BC%95%E5%85%A5-guess-number"><span class="toc-text">Ch2 引入 - guess_number</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-%E5%88%9B%E5%BB%BA%E5%8F%98%E9%87%8F"><span class="toc-text">2.1 创建变量</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-%E4%BB%8E%E6%A0%87%E5%87%86%E8%BE%93%E5%85%A5%E8%AF%BB%E5%8F%96"><span class="toc-text">2.2 从标准输入读取</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-crate"><span class="toc-text">2.3 crate</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-3-1-%E5%AF%BC%E5%85%A5%E5%A4%96%E9%83%A8crate"><span class="toc-text">2.3.1 导入外部crate</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-3-2-%E6%9B%B4%E6%96%B0crate"><span class="toc-text">2.3.2 更新crate</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-3-3-%E8%8E%B7%E5%8F%96%E6%89%80%E6%9C%89%E6%9C%AC%E5%9C%B0%E4%BE%9D%E8%B5%96%E6%8F%90%E4%BE%9B%E7%9A%84%E6%96%87%E6%A1%A3"><span class="toc-text">2.3.3 获取所有本地依赖提供的文档</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch3-%E5%B8%B8%E8%A7%81%E7%BC%96%E7%A8%8B%E6%A6%82%E5%BF%B5"><span class="toc-text">Ch3 常见编程概念</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-1-%E5%8F%98%E9%87%8F%E5%92%8C%E5%8F%AF%E5%8F%98%E6%80%A7"><span class="toc-text">3.1 变量和可变性</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-1-%E5%8F%98%E9%87%8F%E5%92%8C%E5%B8%B8%E9%87%8F%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-text">3.1.1 变量和常量的区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-2-%E9%9A%90%E8%97%8F"><span class="toc-text">3.1.2 隐藏</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-2-%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="toc-text">3.2 数据类型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-1-%E6%A0%87%E9%87%8F%E7%B1%BB%E5%9E%8B"><span class="toc-text">3.2.1 标量类型</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%95%B4%E5%9E%8B"><span class="toc-text">整型</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%B5%AE%E7%82%B9%E5%9E%8B"><span class="toc-text">浮点型</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%B8%83%E5%B0%94%E5%9E%8B"><span class="toc-text">布尔型</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%AD%97%E7%AC%A6%E7%B1%BB%E5%9E%8B"><span class="toc-text">字符类型</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-2-%E5%A4%8D%E5%90%88%E7%B1%BB%E5%9E%8B"><span class="toc-text">3.2.2 复合类型</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%85%83%E7%BB%84%E7%B1%BB%E5%9E%8B"><span class="toc-text">元组类型</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%95%B0%E7%BB%84%E7%B1%BB%E5%9E%8B"><span class="toc-text">数组类型</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-%E5%87%BD%E6%95%B0"><span class="toc-text">3.3 函数</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-1-%E5%85%B7%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC%E7%9A%84%E5%87%BD%E6%95%B0"><span class="toc-text">3.3.1 具有返回值的函数</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4-%E6%B3%A8%E9%87%8A"><span class="toc-text">3.4 注释</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-%E6%8E%A7%E5%88%B6%E6%B5%81"><span class="toc-text">3.5 控制流</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-5-1-if%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="toc-text">3.5.1 if表达式</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%9C%A8let%E8%AF%AD%E5%8F%A5%E4%B8%AD%E4%BD%BF%E7%94%A8if"><span class="toc-text">在let语句中使用if</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-5-2-%E5%BE%AA%E7%8E%AF"><span class="toc-text">3.5.2 循环</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#loop"><span class="toc-text">loop</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#while"><span class="toc-text">while</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#for%E9%81%8D%E5%8E%86%E9%9B%86%E5%90%88"><span class="toc-text">for遍历集合</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch4-%E6%89%80%E6%9C%89%E6%9D%83"><span class="toc-text">Ch4 所有权</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#4-1-%E4%BB%80%E4%B9%88%E6%98%AF%E6%89%80%E6%9C%89%E6%9D%83"><span class="toc-text">4.1 什么是所有权</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-1-%E6%89%80%E6%9C%89%E6%9D%83%E8%A7%84%E5%88%99%EF%BC%9A"><span class="toc-text">4.1.1 所有权规则：</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-2-%E5%8F%98%E9%87%8F%E4%BD%9C%E7%94%A8%E5%9F%9F"><span class="toc-text">4.1.2 变量作用域</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-3-String%E7%B1%BB%E5%9E%8B"><span class="toc-text">4.1.3 String类型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-4-%E5%86%85%E5%AD%98%E4%B8%8E%E5%88%86%E9%85%8D"><span class="toc-text">4.1.4 内存与分配</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-5-%E5%AD%98%E5%82%A8%E5%9C%A8%E5%A0%86%E4%B8%8A%E7%9A%84%E5%8F%98%E9%87%8F"><span class="toc-text">4.1.5 存储在堆上的变量</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E7%A7%BB%E5%8A%A8"><span class="toc-text">1. 移动</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%85%8B%E9%9A%86"><span class="toc-text">克隆</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-6-%E6%89%80%E6%9C%89%E6%9D%83%E4%B8%8E%E5%87%BD%E6%95%B0"><span class="toc-text">4.1.6 所有权与函数</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-2-%E5%BC%95%E7%94%A8%E4%B8%8E%E5%80%9F%E7%94%A8"><span class="toc-text">4.2 引用与借用</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-1-%E5%8F%AF%E5%8F%98%E5%BC%95%E7%94%A8"><span class="toc-text">4.2.1 可变引用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-2-%E6%82%AC%E5%9E%82%E5%BC%95%E7%94%A8"><span class="toc-text">4.2.2 悬垂引用</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-3-Slice%E7%B1%BB%E5%9E%8B"><span class="toc-text">4.3 Slice类型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-1-%E5%AD%97%E7%AC%A6%E4%B8%B2slice"><span class="toc-text">4.3.1 字符串slice</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-2-%E5%85%B6%E4%BB%96%E7%B1%BB%E5%9E%8B%E7%9A%84slice"><span class="toc-text">4.3.2 其他类型的slice</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch5-%E7%BB%93%E6%9E%84%E4%BD%93"><span class="toc-text">Ch5 结构体</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#5-1-%E7%BB%93%E6%9E%84%E4%BD%93%E7%9A%84%E5%AE%9A%E4%B9%89%E5%92%8C%E5%AE%9E%E4%BE%8B%E5%8C%96"><span class="toc-text">5.1 结构体的定义和实例化</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-1-1-%E5%85%83%E7%BB%84%E7%BB%93%E6%9E%84%E4%BD%93"><span class="toc-text">5.1.1 元组结构体</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-1-2-%E7%BB%93%E6%9E%84%E4%BD%93%E6%95%B0%E6%8D%AE%E7%9A%84%E6%89%80%E6%9C%89%E6%9D%83"><span class="toc-text">5.1.2 结构体数据的所有权</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-2-%E7%BB%93%E6%9E%84%E4%BD%93%E5%BC%95%E7%94%A8%E5%92%8C%E6%89%93%E5%8D%B0"><span class="toc-text">5.2 结构体引用和打印</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-2-1-%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8%E7%BB%93%E6%9E%84%E4%BD%93"><span class="toc-text">5.2.1 函数调用结构体</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-2-2-%E7%BB%93%E6%9E%84%E4%BD%93%E6%89%93%E5%8D%B0"><span class="toc-text">5.2.2 结构体打印</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-3-%E6%96%B9%E6%B3%95%E8%AF%AD%E6%B3%95"><span class="toc-text">5.3 方法语法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-3-1-%E5%85%B3%E8%81%94%E5%87%BD%E6%95%B0"><span class="toc-text">5.3.1 关联函数</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch6-%E6%9E%9A%E4%B8%BE%E5%92%8C%E6%A8%A1%E5%BC%8F%E5%8C%B9%E9%85%8D"><span class="toc-text">Ch6 枚举和模式匹配</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#6-1-%E5%AE%9A%E4%B9%89%E6%9E%9A%E4%B8%BE"><span class="toc-text">6.1 定义枚举</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#6-1-1-Option%E6%9E%9A%E4%B8%BE"><span class="toc-text">6.1.1 Option枚举</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-2-match%E6%8E%A7%E5%88%B6%E6%B5%81%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-text">6.2 match控制流运算符</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-1-%E5%8C%B9%E9%85%8DOption-T"><span class="toc-text">6.2.1 匹配Option&lt;T&gt;</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-2-%E9%80%9A%E9%85%8D%E7%AC%A6"><span class="toc-text">6.2.2 _通配符</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-3-if-let-%E7%AE%80%E5%8D%95%E6%8E%A7%E5%88%B6%E6%B5%81"><span class="toc-text">6.3 if let 简单控制流</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch7-%E4%BD%BF%E7%94%A8%E5%8C%85%E3%80%81Crate%E5%92%8C%E6%A8%A1%E5%9D%97%E7%AE%A1%E7%90%86%E9%A1%B9%E7%9B%AE"><span class="toc-text">Ch7 使用包、Crate和模块管理项目</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#7-1-%E5%8C%85%E5%92%8Ccrate"><span class="toc-text">7.1 包和crate</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-2-%E6%A8%A1%E5%9D%97"><span class="toc-text">7.2 模块</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-3-%E5%BC%95%E7%94%A8%E6%A8%A1%E5%9D%97%E6%A0%91%E4%B8%AD%E9%A1%B9%E7%9A%84%E8%B7%AF%E5%BE%84"><span class="toc-text">7.3 引用模块树中项的路径</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#7-3-1-%E4%BD%BF%E7%94%A8pub%E5%85%B3%E9%94%AE%E5%AD%97%E6%9A%B4%E9%9C%B2%E8%B7%AF%E5%BE%84"><span class="toc-text">7.3.1 使用pub关键字暴露路径</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-3-2-%E4%BD%BF%E7%94%A8super%E8%B5%B7%E5%A7%8B%E7%9A%84%E7%9B%B8%E5%AF%B9%E8%B7%AF%E5%BE%84"><span class="toc-text">7.3.2 使用super起始的相对路径</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-3-3-%E5%88%9B%E5%BB%BA%E5%85%AC%E6%9C%89%E7%9A%84%E7%BB%93%E6%9E%84%E4%BD%93%E5%92%8C%E6%9E%9A%E4%B8%BE"><span class="toc-text">7.3.3 创建公有的结构体和枚举</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-4-use%E5%85%B3%E9%94%AE%E5%AD%97"><span class="toc-text">7.4 use关键字</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#7-4-1-%E4%BD%BF%E7%94%A8%E5%B5%8C%E5%A5%97%E8%B7%AF%E5%BE%84%E7%B2%BE%E7%AE%80%E4%BB%A3%E7%A0%81"><span class="toc-text">7.4.1 使用嵌套路径精简代码</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-4-2-glob%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-text">7.4.2 glob运算符</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-5-%E5%B0%86%E6%A8%A1%E5%9D%97%E5%88%86%E5%89%B2%E8%BF%9B%E4%B8%8D%E5%90%8C%E6%96%87%E4%BB%B6"><span class="toc-text">7.5 将模块分割进不同文件</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch8-%E5%B8%B8%E8%A7%81%E9%9B%86%E5%90%88"><span class="toc-text">Ch8 常见集合</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#8-1-vector"><span class="toc-text">8.1 vector</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#8-1-1-%E6%96%B0%E5%BB%BAvector"><span class="toc-text">8.1.1 新建vector</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-1-2-vector%E6%B7%BB%E5%8A%A0%E5%85%83%E7%B4%A0"><span class="toc-text">8.1.2 vector添加元素</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-1-3-%E8%AF%BB%E5%8F%96vector%E5%85%83%E7%B4%A0"><span class="toc-text">8.1.3 读取vector元素</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-1-4-%E9%81%8D%E5%8E%86vector%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0"><span class="toc-text">8.1.4 遍历vector中的元素</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-1-5-%E7%BB%93%E5%90%88%E6%9E%9A%E4%B8%BE%E6%9D%A5%E5%AD%98%E5%82%A8%E5%A4%9A%E7%A7%8D%E7%B1%BB%E5%9E%8B"><span class="toc-text">8.1.5 结合枚举来存储多种类型</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-2-%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-text">8.2 字符串</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-1-%E6%96%B0%E5%BB%BA%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-text">8.2.1 新建字符串</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-2-%E6%9B%B4%E6%96%B0%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-text">8.2.2 更新字符串</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-3-%E7%B4%A2%E5%BC%95%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-text">8.2.3 索引字符串</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-4-%E9%81%8D%E5%8E%86%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-text">8.2.4 遍历字符串</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-3-%E5%93%88%E5%B8%8Cmap"><span class="toc-text">8.3 哈希map</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#8-3-1-%E6%96%B0%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%93%88%E5%B8%8Cmap"><span class="toc-text">8.3.1 新建一个哈希map</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-3-2-%E5%93%88%E5%B8%8Cmap%E5%92%8C%E6%89%80%E6%9C%89%E6%9D%83"><span class="toc-text">8.3.2 哈希map和所有权</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-3-3-%E8%AE%BF%E9%97%AE%E5%93%88%E5%B8%8Cmap%E4%B8%AD%E7%9A%84%E5%80%BC"><span class="toc-text">8.3.3 访问哈希map中的值</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-3-4-%E9%81%8D%E5%8E%86%E5%93%88%E5%B8%8Cmap"><span class="toc-text">8.3.4 遍历哈希map</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-3-5-%E6%9B%B4%E6%96%B0%E5%93%88%E5%B8%8Cmap"><span class="toc-text">8.3.5 更新哈希map</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch9-%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86"><span class="toc-text">Ch9 错误处理</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#9-1-panic-%E4%B8%8E%E4%B8%8D%E5%8F%AF%E6%81%A2%E5%A4%8D%E7%9A%84%E9%94%99%E8%AF%AF"><span class="toc-text">9.1 panic!与不可恢复的错误</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#9-1-1-backtrace"><span class="toc-text">9.1.1 backtrace</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-2-Result%E4%B8%8E%E5%8F%AF%E6%81%A2%E5%A4%8D%E7%9A%84%E9%94%99%E8%AF%AF"><span class="toc-text">9.2 Result与可恢复的错误</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#9-2-1-%E5%8C%B9%E9%85%8D%E4%B8%8D%E5%90%8C%E7%9A%84%E9%94%99%E8%AF%AF"><span class="toc-text">9.2.1 匹配不同的错误</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-2-2-unwrap"><span class="toc-text">9.2.2 unwrap</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-2-3-expect"><span class="toc-text">9.2.3 expect</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-2-4-%E4%BC%A0%E6%92%AD%E9%94%99%E8%AF%AF"><span class="toc-text">9.2.4 传播错误</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-3-panic-%E7%9A%84%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">9.3 panic!的使用场景</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch10-%E6%B3%9B%E5%9E%8B%E3%80%81trait%E5%92%8C%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="toc-text">Ch10 泛型、trait和生命周期</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#10-1-%E6%B3%9B%E5%9E%8B"><span class="toc-text">10.1 泛型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-1-%E5%9C%A8%E5%87%BD%E6%95%B0%E5%AE%9A%E4%B9%89%E4%B8%AD%E4%BD%BF%E7%94%A8%E6%B3%9B%E5%9E%8B"><span class="toc-text">10.1.1 在函数定义中使用泛型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-2-%E7%BB%93%E6%9E%84%E4%BD%93%E5%AE%9A%E4%B9%89%E4%B8%AD%E7%9A%84%E6%B3%9B%E5%9E%8B"><span class="toc-text">10.1.2 结构体定义中的泛型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-3-%E6%9E%9A%E4%B8%BE%E5%AE%9A%E4%B9%89%E4%B8%AD%E7%9A%84%E6%B3%9B%E5%9E%8B"><span class="toc-text">10.1.3 枚举定义中的泛型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-4-%E6%96%B9%E6%B3%95%E5%AE%9A%E4%B9%89%E4%B8%AD%E7%9A%84%E6%B3%9B%E5%9E%8B"><span class="toc-text">10.1.4 方法定义中的泛型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-5-%E6%B3%9B%E5%9E%8B%E4%BB%A3%E7%A0%81%E7%9A%84%E6%80%A7%E8%83%BD"><span class="toc-text">10.1.5 泛型代码的性能</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-2-trait%EF%BC%9A%E5%AE%9A%E4%B9%89%E5%85%B1%E4%BA%AB%E7%9A%84%E8%A1%8C%E4%B8%BA"><span class="toc-text">10.2 trait：定义共享的行为</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-1-%E5%AE%9A%E4%B9%89%E5%B9%B6%E4%BD%BF%E7%94%A8trait"><span class="toc-text">10.2.1 定义并使用trait</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-2-%E9%BB%98%E8%AE%A4%E5%AE%9E%E7%8E%B0"><span class="toc-text">10.2.2 默认实现</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-3-trait%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0"><span class="toc-text">10.2.3 trait作为参数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-4-%E8%BF%94%E5%9B%9Etrait%E7%B1%BB%E5%9E%8B"><span class="toc-text">10.2.4 返回trait类型</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-3-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E4%B8%8E%E5%BC%95%E7%94%A8%E6%9C%89%E6%95%88%E6%80%A7"><span class="toc-text">10.3 生命周期与引用有效性</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-1-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%98%B2%E6%AD%A2%E6%82%AC%E5%9E%82%E5%BC%95%E7%94%A8"><span class="toc-text">10.3.1 生命周期防止悬垂引用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-2-%E5%87%BD%E6%95%B0%E7%9A%84%E6%B3%9B%E5%9E%8B%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="toc-text">10.3.2 函数的泛型生命周期</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E6%B3%A8%E8%A7%A3%E8%AF%AD%E6%B3%95"><span class="toc-text">生命周期注解语法</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%87%BD%E6%95%B0%E7%AD%BE%E5%90%8D%E4%B8%AD%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E6%B3%A8%E8%A7%A3"><span class="toc-text">函数签名中的生命周期注解</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-3-%E7%BB%93%E6%9E%84%E4%BD%93%E5%AE%9A%E4%B9%89%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E6%B3%A8%E8%A7%A3"><span class="toc-text">10.3.3 结构体定义生命周期注解</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-4-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E7%9C%81%E7%95%A5"><span class="toc-text">10.3.4 生命周期省略</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-5-%E6%96%B9%E6%B3%95%E5%AE%9A%E4%B9%89%E4%B8%AD%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E6%B3%A8%E8%A7%A3"><span class="toc-text">10.3.5 方法定义中的生命周期注解</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-6-%E9%9D%99%E6%80%81%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="toc-text">10.3.6 静态生命周期</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch11-%E7%BC%96%E5%86%99%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95"><span class="toc-text">Ch11 编写自动化测试</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#11-1-%E5%A6%82%E4%BD%95%E7%BC%96%E5%86%99%E6%B5%8B%E8%AF%95"><span class="toc-text">11.1 如何编写测试</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#11-1-1-%E6%B5%8B%E8%AF%95%E5%87%BD%E6%95%B0%E5%89%96%E6%9E%90"><span class="toc-text">11.1.1 测试函数剖析</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#11-1-2-%E4%BD%BF%E7%94%A8assert-%E5%AE%8F%E6%9D%A5%E6%A3%80%E6%9F%A5%E7%BB%93%E6%9E%9C"><span class="toc-text">11.1.2 使用assert!宏来检查结果</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#11-1-3-%E4%BD%BF%E7%94%A8assert-eq-%E5%92%8Cassert-ne-%E5%AE%8F%E6%9D%A5%E6%B5%8B%E8%AF%95%E7%9B%B8%E7%AD%89"><span class="toc-text">11.1.3 使用assert_eq!和assert_ne!宏来测试相等</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#11-1-4-%E8%87%AA%E5%AE%9A%E4%B9%89%E5%A4%B1%E8%B4%A5%E4%BF%A1%E6%81%AF"><span class="toc-text">11.1.4 自定义失败信息</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#11-1-5-%E4%BD%BF%E7%94%A8-should-panic-%E6%A3%80%E6%9F%A5-panic"><span class="toc-text">11.1.5 使用 should_panic 检查 panic</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#11-1-6-%E5%B0%86-Result-T-E-%E7%94%A8%E4%BA%8E%E6%B5%8B%E8%AF%95"><span class="toc-text">11.1.6 将 Result&lt;T, E&gt; 用于测试</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#11-2-%E8%BF%90%E8%A1%8C%E6%B5%8B%E8%AF%95"><span class="toc-text">11.2 运行测试</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#11-2-1-%E5%B9%B6%E8%A1%8C%E6%88%96%E8%BF%9E%E7%BB%AD%E7%9A%84%E8%BF%90%E8%A1%8C%E6%B5%8B%E8%AF%95"><span class="toc-text">11.2.1 并行或连续的运行测试</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#11-2-2-%E6%98%BE%E7%A4%BA%E5%87%BD%E6%95%B0%E8%BE%93%E5%87%BA"><span class="toc-text">11.2.2 显示函数输出</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#11-2-3-%E9%80%9A%E8%BF%87%E6%8C%87%E5%AE%9A%E5%90%8D%E5%AD%97%E6%9D%A5%E8%BF%90%E8%A1%8C%E9%83%A8%E5%88%86%E6%B5%8B%E8%AF%95"><span class="toc-text">11.2.3 通过指定名字来运行部分测试</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#11-2-4-%E5%BF%BD%E7%95%A5%E6%9F%90%E4%BA%9B%E6%B5%8B%E8%AF%95"><span class="toc-text">11.2.4 忽略某些测试</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#11-3-%E6%B5%8B%E8%AF%95%E7%9A%84%E7%BB%84%E7%BB%87%E7%BB%93%E6%9E%84"><span class="toc-text">11.3 测试的组织结构</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#11-3-1-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95"><span class="toc-text">11.3.1 单元测试</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%B5%8B%E8%AF%95%E6%A8%A1%E5%9D%97"><span class="toc-text">测试模块</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#11-3-2-%E9%9B%86%E6%88%90%E6%B5%8B%E8%AF%95"><span class="toc-text">11.3.2 集成测试</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch12-I-O%E9%A1%B9%E7%9B%AE%EF%BC%9A%E5%91%BD%E4%BB%A4%E8%A1%8C%E7%A8%8B%E5%BA%8F"><span class="toc-text">Ch12 I&#x2F;O项目：命令行程序</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#12-1-%E6%8E%A5%E5%8F%97%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0"><span class="toc-text">12.1 接受命令行参数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#12-2-%E8%AF%BB%E5%8F%96%E6%96%87%E4%BB%B6"><span class="toc-text">12.2 读取文件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#12-3-%E9%87%8D%E6%9E%84%E6%94%B9%E8%BF%9B%E6%A8%A1%E5%9D%97%E6%80%A7%E5%92%8C%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86"><span class="toc-text">12.3 重构改进模块性和错误处理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#12-4-%E9%87%87%E7%94%A8%E6%B5%8B%E8%AF%95%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91%E5%AE%8C%E5%96%84%E5%BA%93%E7%9A%84%E5%8A%9F%E8%83%BD"><span class="toc-text">12.4 采用测试驱动开发完善库的功能</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#12-6-%E5%B0%86%E9%94%99%E8%AF%AF%E4%BF%A1%E6%81%AF%E8%BE%93%E5%87%BA%E5%88%B0%E6%A0%87%E5%87%86%E9%94%99%E8%AF%AF"><span class="toc-text">12.6 将错误信息输出到标准错误</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch13-%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%92%8C%E9%97%AD%E5%8C%85"><span class="toc-text">Ch13 迭代器和闭包</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#13-1-%E9%97%AD%E5%8C%85"><span class="toc-text">13.1 闭包</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#13-1-1-%E5%AE%9A%E4%B9%89%E9%97%AD%E5%8C%85"><span class="toc-text">13.1.1 定义闭包</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#13-1-2-%E9%97%AD%E5%8C%85%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD%E5%92%8C%E6%B3%A8%E8%A7%A3"><span class="toc-text">13.1.2 闭包类型推断和注解</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#13-1-3-%E4%BD%BF%E7%94%A8%E5%B8%A6%E6%9C%89%E6%B3%9B%E5%9E%8B%E5%92%8CFn-trait%E7%9A%84%E9%97%AD%E5%8C%85"><span class="toc-text">13.1.3 使用带有泛型和Fn trait的闭包</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#13-1-4-%E9%97%AD%E5%8C%85%E4%BC%9A%E6%8D%95%E8%8E%B7%E5%85%B6%E7%8E%AF%E5%A2%83"><span class="toc-text">13.1.4 闭包会捕获其环境</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#13-2-%E8%BF%AD%E4%BB%A3%E5%99%A8"><span class="toc-text">13.2 迭代器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#13-2-1-Iterator-trait-%E5%92%8C-next%E6%96%B9%E6%B3%95"><span class="toc-text">13.2.1 Iterator trait 和 next方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#13-2-2-%E6%B6%88%E8%B4%B9%E9%80%82%E9%85%8D%E5%99%A8"><span class="toc-text">13.2.2 消费适配器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#13-2-3-%E8%BF%AD%E4%BB%A3%E5%99%A8%E9%80%82%E9%85%8D%E5%99%A8"><span class="toc-text">13.2.3 迭代器适配器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#13-2-4-%E5%88%9B%E5%BB%BA%E8%87%AA%E5%AE%9A%E4%B9%89%E8%BF%AD%E4%BB%A3%E5%99%A8"><span class="toc-text">13.2.4 创建自定义迭代器</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch14-%E8%BF%9B%E4%B8%80%E6%AD%A5%E8%AE%A4%E8%AF%86Cargo%E5%92%8CCrates-io"><span class="toc-text">Ch14 进一步认识Cargo和Crates.io</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#14-1-%E9%87%87%E7%94%A8%E5%8F%91%E5%B8%83%E9%85%8D%E7%BD%AE%E8%87%AA%E5%AE%9A%E4%B9%89%E6%9E%84%E5%BB%BA"><span class="toc-text">14.1 采用发布配置自定义构建</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#14-2-%E5%B0%86-crate-%E5%8F%91%E5%B8%83%E5%88%B0-Crates-io"><span class="toc-text">14.2 将 crate 发布到 Crates.io</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#14-3-Cargo%E5%B7%A5%E4%BD%9C%E7%A9%BA%E9%97%B4"><span class="toc-text">14.3 Cargo工作空间</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#14-4-%E4%BB%8E-Crates-io-%E5%AE%89%E8%A3%85%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%96%87%E4%BB%B6"><span class="toc-text">14.4 从 Crates.io 安装二进制文件</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch15-%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88"><span class="toc-text">Ch15 智能指针</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#15-1-Box-T"><span class="toc-text">15.1 Box&lt;T&gt;</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#15-1-1-Box%E5%88%9B%E5%BB%BA%E9%80%92%E5%BD%92%E7%B1%BB%E5%9E%8B"><span class="toc-text">15.1.1 Box创建递归类型</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BB%A5cons-list%E4%B8%BA%E4%BE%8B"><span class="toc-text">以cons list为例</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8Box-T-%E7%BB%99%E9%80%92%E5%BD%92%E7%B1%BB%E5%9E%8B%E4%B8%80%E4%B8%AA%E5%B7%B2%E7%9F%A5%E7%9A%84%E5%A4%A7%E5%B0%8F"><span class="toc-text">使用Box&lt;T&gt;给递归类型一个已知的大小</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-2-Deref-trait"><span class="toc-text">15.2 Deref trait</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#15-2-1-%E5%83%8F%E5%BC%95%E7%94%A8%E4%B8%80%E6%A0%B7%E4%BD%BF%E7%94%A8-Box-T"><span class="toc-text">15.2.1 像引用一样使用 Box&lt;T&gt;</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#15-2-2-%E8%87%AA%E5%AE%9A%E4%B9%89%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88"><span class="toc-text">15.2.2 自定义智能指针</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#15-2-3-%E5%9C%A8%E8%87%AA%E5%AE%9A%E4%B9%89%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88%E5%AE%9E%E7%8E%B0-Deref-trait"><span class="toc-text">15.2.3 在自定义智能指针实现 Deref trait</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#15-2-4-%E5%87%BD%E6%95%B0%E5%92%8C%E6%96%B9%E6%B3%95%E7%9A%84%E9%9A%90%E5%BC%8F%E8%A7%A3%E5%BC%95%E7%94%A8%E5%BC%BA%E5%88%B6%E5%A4%9A%E6%80%81"><span class="toc-text">15.2.4 函数和方法的隐式解引用强制多态</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-3-Drop-trait"><span class="toc-text">15.3 Drop trait</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#15-3-1-%E9%80%9A%E8%BF%87-std-mem-drop-%E6%8F%90%E6%97%A9%E4%B8%A2%E5%BC%83%E5%80%BC"><span class="toc-text">15.3.1 通过 std::mem::drop 提早丢弃值</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-4-Rc-T-%E5%BC%95%E7%94%A8%E8%AE%A1%E6%95%B0%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88"><span class="toc-text">15.4 Rc&lt;T&gt; 引用计数智能指针</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#15-4-1-%E4%BD%BF%E7%94%A8-Rc-T-%E5%85%B1%E4%BA%AB%E6%95%B0%E6%8D%AE"><span class="toc-text">15.4.1 使用 Rc&lt;T&gt; 共享数据</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-5-RefCell-T-%E5%92%8C%E5%86%85%E9%83%A8%E5%8F%AF%E5%8F%98%E6%80%A7%E6%A8%A1%E5%BC%8F"><span class="toc-text">15.5 RefCell&lt;T&gt; 和内部可变性模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#15-6-%E5%BC%95%E7%94%A8%E5%BE%AA%E7%8E%AF%E4%B8%8E%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F"><span class="toc-text">15.6 引用循环与内存泄漏</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch16-%E5%B9%B6%E5%8F%91"><span class="toc-text">Ch16 并发</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#16-1-%E4%BD%BF%E7%94%A8%E7%BA%BF%E7%A8%8B%E5%90%8C%E6%97%B6%E8%BF%90%E8%A1%8C%E4%BB%A3%E7%A0%81"><span class="toc-text">16.1 使用线程同时运行代码</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#16-1-1-%E4%BD%BF%E7%94%A8-spawn-%E5%88%9B%E5%BB%BA%E6%96%B0%E7%BA%BF%E7%A8%8B"><span class="toc-text">16.1.1 使用 spawn 创建新线程</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#16-1-2-%E4%BD%BF%E7%94%A8-join-%E7%AD%89%E5%BE%85%E6%89%80%E6%9C%89%E7%BA%BF%E7%A8%8B%E7%BB%93%E6%9D%9F"><span class="toc-text">16.1.2 使用 join 等待所有线程结束</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#16-1-3-%E7%BA%BF%E7%A8%8B%E4%B8%8E-move-%E9%97%AD%E5%8C%85"><span class="toc-text">16.1.3 线程与 move 闭包</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#16-2-%E7%BA%BF%E7%A8%8B%E9%97%B4%E6%B6%88%E6%81%AF%E4%BC%A0%E9%80%92"><span class="toc-text">16.2 线程间消息传递</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#16-3-%E5%85%B1%E4%BA%AB%E7%8A%B6%E6%80%81%E5%B9%B6%E5%8F%91"><span class="toc-text">16.3 共享状态并发</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#16-3-1-%E4%BA%92%E6%96%A5%E5%99%A8"><span class="toc-text">16.3.1 互斥器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#16-3-2-%E5%9C%A8%E7%BA%BF%E7%A8%8B%E9%97%B4%E5%85%B1%E4%BA%AB-Mutex-T"><span class="toc-text">16.3.2 在线程间共享 Mutex&lt;T&gt;</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch17-Rust%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1"><span class="toc-text">Ch17 Rust面向对象</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#17-1-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%AF%AD%E8%A8%80%E7%9A%84%E7%89%B9%E5%BE%81"><span class="toc-text">17.1 面向对象语言的特征</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#17-2-%E4%B8%BA%E4%BD%BF%E7%94%A8%E4%B8%8D%E5%90%8C%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%80%BC%E8%80%8C%E8%AE%BE%E8%AE%A1%E7%9A%84-trait-%E5%AF%B9%E8%B1%A1"><span class="toc-text">17.2 为使用不同类型的值而设计的 trait 对象</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#17-3-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="toc-text">17.3 面向对象设计模式的实现</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch18-%E6%A8%A1%E5%BC%8F"><span class="toc-text">Ch18 模式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#18-1-%E7%94%A8%E5%88%B0%E6%A8%A1%E5%BC%8F%E7%9A%84%E4%BD%8D%E7%BD%AE"><span class="toc-text">18.1 用到模式的位置</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#18-1-1-match%E5%88%86%E6%94%AF"><span class="toc-text">18.1.1 match分支</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#18-1-2-if-let-%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="toc-text">18.1.2 if let 表达式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#18-1-3-while-let-%E6%9D%A1%E4%BB%B6%E5%BE%AA%E7%8E%AF"><span class="toc-text">18.1.3 while let 条件循环</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#18-1-4-for%E5%BE%AA%E7%8E%AF"><span class="toc-text">18.1.4 for循环</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#18-1-5-let%E8%AF%AD%E5%8F%A5"><span class="toc-text">18.1.5 let语句</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#18-1-6-%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0"><span class="toc-text">18.1.6 函数参数</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#18-2-%E5%8F%AF%E5%8F%8D%E9%A9%B3%E5%92%8C%E4%B8%8D%E5%8F%AF%E5%8F%8D%E9%A9%B3"><span class="toc-text">18.2 可反驳和不可反驳</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#18-3-%E6%A8%A1%E5%BC%8F%E8%AF%AD%E6%B3%95"><span class="toc-text">18.3 模式语法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#18-3-1-%E5%8C%B9%E9%85%8D%E5%AD%97%E9%9D%A2%E5%80%BC"><span class="toc-text">18.3.1 匹配字面值</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#18-3-2-%E5%8C%B9%E9%85%8D%E5%91%BD%E5%90%8D%E5%8F%98%E9%87%8F"><span class="toc-text">18.3.2 匹配命名变量</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#18-3-3-%E5%A4%9A%E4%B8%AA%E6%A8%A1%E5%BC%8F"><span class="toc-text">18.3.3 多个模式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#18-3-4-%E9%80%9A%E8%BF%87-%E2%80%A6-%E5%8C%B9%E9%85%8D%E5%80%BC%E7%9A%84%E8%8C%83%E5%9B%B4"><span class="toc-text">18.3.4 通过 …&#x3D; 匹配值的范围</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#18-3-5-%E5%BF%BD%E7%95%A5%E6%A8%A1%E5%BC%8F%E4%B8%AD%E7%9A%84%E5%80%BC"><span class="toc-text">18.3.5 忽略模式中的值</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#18-3-6-%E5%8C%B9%E9%85%8D%E5%AE%88%E5%8D%AB"><span class="toc-text">18.3.6 匹配守卫</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#18-3-7-%E7%BB%91%E5%AE%9A"><span class="toc-text">18.3.7 @绑定</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Ch19-%E9%AB%98%E7%BA%A7%E7%89%B9%E5%BE%81"><span class="toc-text">Ch19 高级特征</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#19-1-%E4%B8%8D%E5%AE%89%E5%85%A8%E7%9A%84Rust"><span class="toc-text">19.1 不安全的Rust</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#19-2-%E9%AB%98%E7%BA%A7trait"><span class="toc-text">19.2 高级trait</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#19-3-%E9%AB%98%E7%BA%A7%E7%B1%BB%E5%9E%8B"><span class="toc-text">19.3 高级类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#19-4-%E9%AB%98%E7%BA%A7%E5%87%BD%E6%95%B0%E4%B8%8E%E9%97%AD%E5%8C%85"><span class="toc-text">19.4 高级函数与闭包</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#19-5-%E5%AE%8F"><span class="toc-text">19.5 宏</span></a></li></ol></li></ol>
    </div>
  </section>


  


</aside>



        
        
          <!--此文件用来存放一些不方便取值的变量-->
<!--思路大概是将值藏到重加载的区域内-->

<script>
  window.pdata={}
  pdata.ispage=true;
  pdata.postTitle="Rust - Learn";
  pdata.commentPath="";
  pdata.commentPlaceholder="";

  var l_header=document.getElementById("l_header");
  
  l_header.classList.add("show");
  
</script>

        
      </div>
      
  
  <footer class="footer clearfix">
    <br><br>
    
      
        <div class='copyright'>
        <p><a target="_blank" rel="noopener" href="https://github.com/Schenk75/Schenk75.github.io">Copyright © 2020-2022 Schenk</a></p>

        </div>
      
    
  </footer>


      <a id="s-top" class="fas fa-arrow-up fa-fw" href='javascript:void(0)'></a>
    </div>
  </div>
  <div>
    <script>
window.volantis={};
window.volantis.loadcss=document.getElementById("loadcss");
/********************脚本懒加载函数********************************/
function loadScript(src, cb) {
var HEAD = document.getElementsByTagName('head')[0] || document.documentElement;
var script = document.createElement('script');
script.setAttribute('type','text/javascript');
if (cb) script.onload = cb;
script.setAttribute('src', src);
HEAD.appendChild(script);
}
//https://github.com/filamentgroup/loadCSS
var loadCSS = function( href, before, media, attributes ){
	var doc = window.document;
	var ss = doc.createElement( "link" );
	var ref;
	if( before ){
		ref = before;
	}
	else {
		var refs = ( doc.body || doc.getElementsByTagName( "head" )[ 0 ] ).childNodes;
		ref = refs[ refs.length - 1];
	}
	var sheets = doc.styleSheets;
	if( attributes ){
		for( var attributeName in attributes ){
			if( attributes.hasOwnProperty( attributeName ) ){
				ss.setAttribute( attributeName, attributes[attributeName] );
			}
		}
	}
	ss.rel = "stylesheet";
	ss.href = href;
	ss.media = "only x";
	function ready( cb ){
		if( doc.body ){
			return cb();
		}
		setTimeout(function(){
			ready( cb );
		});
	}
	ready( function(){
		ref.parentNode.insertBefore( ss, ( before ? ref : ref.nextSibling ) );
	});
	var onloadcssdefined = function( cb ){
		var resolvedHref = ss.href;
		var i = sheets.length;
		while( i-- ){
			if( sheets[ i ].href === resolvedHref ){
				return cb();
			}
		}
		setTimeout(function() {
			onloadcssdefined( cb );
		});
	};
	function loadCB(){
		if( ss.addEventListener ){
			ss.removeEventListener( "load", loadCB );
		}
		ss.media = media || "all";
	}
	if( ss.addEventListener ){
		ss.addEventListener( "load", loadCB);
	}
	ss.onloadcssdefined = onloadcssdefined;
	onloadcssdefined( loadCB );
	return ss;
};
</script>
<script>
  
  loadCSS("https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.14/css/all.min.css", window.volantis.loadcss);
  
  
  
  
</script>
<!-- required -->

<script src="https://cdn.jsdelivr.net/npm/jquery@3.5/dist/jquery.min.js"></script>

<script>
  function pjax_fancybox() {
    $(".md .gallery").find("img").each(function () { //渲染 fancybox
      var element = document.createElement("a"); // a 标签
      $(element).attr("class", "fancybox");
      $(element).attr("pjax-fancybox", "");  // 过滤 pjax
      $(element).attr("href", $(this).attr("src"));
      if ($(this).attr("data-original")) {
        $(element).attr("href", $(this).attr("data-original"));
      }
      $(element).attr("data-fancybox", "images");
      var caption = "";   // 描述信息
      if ($(this).attr('alt')) {  // 判断当前页面是否存在描述信息
        $(element).attr('data-caption', $(this).attr('alt'));
        caption = $(this).attr('alt');
      }
      var div = document.createElement("div");
      $(div).addClass("fancybox");
      $(this).wrap(div); // 最外层套 div ，其实主要作用还是 class 样式
      var span = document.createElement("span");
      $(span).addClass("image-caption");
      $(span).text(caption); // 加描述
      $(this).after(span);  // 再套一层描述
      $(this).wrap(element);  // 最后套 a 标签
    })
    $(".md .gallery").find("img").fancybox({
      selector: '[data-fancybox="images"]',
      hash: false,
      loop: false,
      closeClick: true,
      helpers: {
        overlay: {closeClick: true}
      },
      buttons: [
        "zoom",
        "close"
      ]
    });
  };
  function SCload_fancybox() {
    if ($(".md .gallery").find("img").length == 0) return;
    loadCSS("https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css", document.getElementById("loadcss"));
    setTimeout(function() {
      loadScript('https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js', pjax_fancybox)
    }, 1);
  };
  $(function () {
    SCload_fancybox();
  });
</script>


<!-- internal -->







  <script defer src="https://cdn.jsdelivr.net/npm/vanilla-lazyload@17.1.0/dist/lazyload.min.js"></script>
<script>
  // https://www.npmjs.com/package/vanilla-lazyload
  // Set the options globally
  // to make LazyLoad self-initialize
  window.lazyLoadOptions = {
    elements_selector: ".lazyload",
    threshold: 0
  };
  // Listen to the initialization event
  // and get the instance of LazyLoad
  window.addEventListener(
    "LazyLoad::Initialized",
    function (event) {
      window.lazyLoadInstance = event.detail.instance;
    },
    false
  );
  document.addEventListener('DOMContentLoaded', function () {
    lazyLoadInstance.update();
  });
  document.addEventListener('pjax:complete', function () {
    lazyLoadInstance.update();
  });
</script>




  
  
    <script>
      window.FPConfig = {
        delay: 0,
        ignoreKeywords: [],
        maxRPS: 5,
        hoverDelay: 25
      };
    </script>
    <script defer src="https://cdn.jsdelivr.net/gh/gijo-varghese/flying-pages@2.1.2/flying-pages.min.js"></script>
  




  <script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
    var clipboard = new ClipboardJS('.btn-copy', {
        target: function (trigger) {
            return trigger.nextElementSibling
        }
    });
    function wait(callback, seconds) {
        var timelag = null;
        timelag = window.setTimeout(callback, seconds)
    }
    function pjax_initCopyCode() {
		if($(".highlight .code pre").length+$(".article pre code").length==0)return;
        var copyHtml = '';
        copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
        copyHtml += '<i class="fas fa-copy"></i><span>COPY</span>';
        copyHtml += '</button>';
        $(".highlight .code pre").before(copyHtml);
        $(".article pre code").before(copyHtml);
        clipboard.off('success').on('success', function (e) {
            let $btn = $(e.trigger);
            $btn.addClass('copied');
            let $icon = $($btn.find('i'));
            $icon.removeClass('fa-copy');
            $icon.addClass('fa-check-circle');
            let $span = $($btn.find('span'));
            $span[0].innerText = 'COPIED';
            wait(function () {
                $icon.removeClass('fa-check-circle');
                $icon.addClass('fa-copy');
                $span[0].innerText = 'COPY'
            }, 2000)
        });
        clipboard.off('error').on('error', function (e) {
            e.clearSelection();
            let $btn = $(e.trigger);
            $btn.addClass('copy-failed');
            let $icon = $($btn.find('i'));
            $icon.removeClass('fa-copy');
            $icon.addClass('fa-times-circle');
            let $span = $($btn.find('span'));
            $span[0].innerText = 'COPY FAILED';
            wait(function () {
                $icon.removeClass('fa-times-circle');
                $icon.addClass('fa-copy');
                $span[0].innerText = 'COPY'
            }, 2000)
        })
    }
    $(function () {
        pjax_initCopyCode()
    });
</script>










  <script defer src="https://cdn.jsdelivr.net/gh/Schenk75/Source@master/tools/busuanzi.pure.mini.js" data-pjax></script>


  
<script src="https://cdn.jsdelivr.net/npm/hexo-theme-volantis@4.1.5/source/js/app.min.js"></script>




  
  
<script src="https://cdn.jsdelivr.net/npm/hexo-theme-volantis@4.1.5/source/js/search.min.js"></script>

  


<!-- optional -->

  <script>
const SearchServiceimagePath="https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@master/img/";
const ROOT =  ("/" || "/").endsWith('/') ? ("/" || "/") : ("//" || "/" );
function listenSearch(){
  
    customSearch = new HexoSearch({
      imagePath: SearchServiceimagePath
    });
  
}
document.addEventListener("DOMContentLoaded", listenSearch);

</script>











  <script defer>

  const LCCounter = {
    app_id: 'u9j57bwJod4EDmXWdxrwuqQT-MdYXbMMI',
    app_key: 'jfHtEKVE24j0IVCGHbvuFClp',
    custom_api_server: '',

    // 查询存储的记录
    getRecord(Counter, url, title) {
      return new Promise(function (resolve, reject) {
        Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify({url})))
          .then(resp => resp.json())
          .then(({results, code, error}) => {
            if (code === 401) {
              throw error;
            }
            if (results && results.length > 0) {
              var record = results[0];
              resolve(record);
            } else {
              Counter('post', '/classes/Counter', {url, title: title, times: 0})
                .then(resp => resp.json())
                .then((record, error) => {
                  if (error) {
                    throw error;
                  }
                  resolve(record);
                }).catch(error => {
                console.error('Failed to create', error);
                reject(error);
              });
            }
          }).catch((error) => {
          console.error('LeanCloud Counter Error:', error);
          reject(error);
        });
      })
    },

    // 发起自增请求
    increment(Counter, incrArr) {
      return new Promise(function (resolve, reject) {
        Counter('post', '/batch', {
          "requests": incrArr
        }).then((res) => {
          res = res.json();
          if (res.error) {
            throw res.error;
          }
          resolve(res);
        }).catch((error) => {
          console.error('Failed to save visitor count', error);
          reject(error);
        });
      });
    },

    // 构建自增请求体
    buildIncrement(objectId) {
      return {
        "method": "PUT",
        "path": `/1.1/classes/Counter/${ objectId }`,
        "body": {
          "times": {
            '__op': 'Increment',
            'amount': 1
          }
        }
      }
    },

    // 校验是否为有效的 UV
    validUV() {
      var key = 'LeanCloudUVTimestamp';
      var flag = localStorage.getItem(key);
      if (flag) {
        // 距离标记小于 24 小时则不计为 UV
        if (new Date().getTime() - parseInt(flag) <= 86400000) {
          return false;
        }
      }
      localStorage.setItem(key, new Date().getTime().toString());
      return true;
    },

    addCount(Counter) {
      var enableIncr = '' === 'true' && window.location.hostname !== 'localhost';
      enableIncr = true;
      var getterArr = [];
      var incrArr = [];
      // 请求 PV 并自增
      var pvCtn = document.querySelector('#lc-sv');
      if (pvCtn || enableIncr) {
        var pvGetter = this.getRecord(Counter, 'http://example.com' + '/#lc-sv', 'Visits').then((record) => {
          incrArr.push(this.buildIncrement(record.objectId))
          var eles = document.querySelectorAll('#lc-sv #number');
          if (eles.length > 0) {
            eles.forEach((el,index,array)=>{
              el.innerText = record.times + 1;
              if (pvCtn) {
                pvCtn.style.display = 'inline';
              }
            })
          }
        });
        getterArr.push(pvGetter);
      }

      // 请求 UV 并自增
      var uvCtn = document.querySelector('#lc-uv');
      if (uvCtn || enableIncr) {
        var uvGetter = this.getRecord(Counter, 'http://example.com' + '/#lc-uv', 'Visitors').then((record) => {
          var vuv = this.validUV();
          vuv && incrArr.push(this.buildIncrement(record.objectId))
          var eles = document.querySelectorAll('#lc-uv #number');
          if (eles.length > 0) {
            eles.forEach((el,index,array)=>{
              el.innerText = record.times + (vuv ? 1 : 0);
              if (uvCtn) {
                uvCtn.style.display = 'inline';
              }
            })
          }
        });
        getterArr.push(uvGetter);
      }

      // 请求文章的浏览数，如果是当前页面就自增
      var allPV = document.querySelectorAll('#lc-pv');
      if (allPV.length > 0 || enableIncr) {
        for (i = 0; i < allPV.length; i++) {
          let pv = allPV[i];
          let title = pv.getAttribute('data-title');
          var url = 'http://example.com' + pv.getAttribute('data-path');
          if (url) {
            var viewGetter = this.getRecord(Counter, url, title).then((record) => {
              // 是当前页面就自增
              let curPath = window.location.pathname;
              if (curPath.includes('index.html')) {
                curPath = curPath.substring(0, curPath.lastIndexOf('index.html'));
              }
              if (pv.getAttribute('data-path') == curPath) {
                incrArr.push(this.buildIncrement(record.objectId));
              }
              if (pv) {
                var ele = pv.querySelector('#lc-pv #number');
                if (ele) {
                  if (pv.getAttribute('data-path') == curPath) {
                    ele.innerText = (record.times || 0) + 1;
                  } else {
                    ele.innerText = record.times || 0;
                  }
                  pv.style.display = 'inline';
                }
              }
            });
            getterArr.push(viewGetter);
          }
        }
      }

      // 如果启动计数自增，批量发起自增请求
      if (enableIncr) {
        Promise.all(getterArr).then(() => {
          incrArr.length > 0 && this.increment(Counter, incrArr);
        })
      }

    },


    fetchData(api_server) {
      var Counter = (method, url, data) => {
        return fetch(`${ api_server }/1.1${ url }`, {
          method,
          headers: {
            'X-LC-Id': this.app_id,
            'X-LC-Key': this.app_key,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data)
        });
      };
      this.addCount(Counter);
    },

    refreshCounter() {
      var api_server = this.app_id.slice(-9) !== '-MdYXbMMI' ? this.custom_api_server : `https://${ this.app_id.slice(0, 8).toLowerCase() }.api.lncldglobal.com`;
      if (api_server) {
        this.fetchData(api_server);
      } else {
        fetch('https://app-router.leancloud.cn/2/route?appId=' + this.app_id)
          .then(resp => resp.json())
          .then(({api_server}) => {
            this.fetchData('https://' + api_server);
          });
      }
    }

  };

  LCCounter.refreshCounter();

  document.addEventListener('pjax:complete', function () {
    LCCounter.refreshCounter();
  });
</script>








<script>
function listennSidebarTOC() {
  const navItems = document.querySelectorAll(".toc li");
  if (!navItems.length) return;
  const sections = [...navItems].map((element) => {
    const link = element.querySelector(".toc-link");
    const target = document.getElementById(
      decodeURI(link.getAttribute("href")).replace("#", "")
    );
    link.addEventListener("click", (event) => {
      event.preventDefault();
      window.scrollTo({
		top: target.offsetTop + 100,
		
		behavior: "smooth"
		
	  });
    });
    return target;
  });

  function activateNavByIndex(target) {
    if (target.classList.contains("active-current")) return;

    document.querySelectorAll(".toc .active").forEach((element) => {
      element.classList.remove("active", "active-current");
    });
    target.classList.add("active", "active-current");
    let parent = target.parentNode;
    while (!parent.matches(".toc")) {
      if (parent.matches("li")) parent.classList.add("active");
      parent = parent.parentNode;
    }
  }

  function findIndex(entries) {
    let index = 0;
    let entry = entries[index];
    if (entry.boundingClientRect.top > 0) {
      index = sections.indexOf(entry.target);
      return index === 0 ? 0 : index - 1;
    }
    for (; index < entries.length; index++) {
      if (entries[index].boundingClientRect.top <= 0) {
        entry = entries[index];
      } else {
        return sections.indexOf(entry.target);
      }
    }
    return sections.indexOf(entry.target);
  }

  function createIntersectionObserver(marginTop) {
    marginTop = Math.floor(marginTop + 10000);
    let intersectionObserver = new IntersectionObserver(
      (entries, observe) => {
        let scrollHeight = document.documentElement.scrollHeight + 100;
        if (scrollHeight > marginTop) {
          observe.disconnect();
          createIntersectionObserver(scrollHeight);
          return;
        }
        let index = findIndex(entries);
        activateNavByIndex(navItems[index]);
      },
      {
        rootMargin: marginTop + "px 0px -100% 0px",
        threshold: 0,
      }
    );
    sections.forEach((element) => {
      element && intersectionObserver.observe(element);
    });
  }
  createIntersectionObserver(document.documentElement.scrollHeight);
}

document.addEventListener("DOMContentLoaded", listennSidebarTOC);
document.addEventListener("pjax:success", listennSidebarTOC);
</script>

<!-- more -->




    
      


<script src="https://cdn.jsdelivr.net/npm/pjax@0.2.8/pjax.min.js"></script>


<script>
    var pjax;
    document.addEventListener('DOMContentLoaded', function () {
      pjax = new Pjax({
        elements: 'a[href]:not([href^="#"]):not([href="javascript:void(0)"]):not([pjax-fancybox])',
        selectors: [
          "title",
          "#l_cover",
          "#pjax-container",
          "#pjax-header-nav-list"
        ],
        cacheBust: false,   // url 地址追加时间戳，用以避免浏览器缓存
        timeout: 5000
      });
    });

    document.addEventListener('pjax:send', function (e) {
      //window.stop(); // 相当于点击了浏览器的停止按钮

      try {
        var currentUrl = window.location.pathname;
        var targetUrl = e.triggerElement.href;
        var banUrl = [""];
        if (banUrl[0] != "") {
          banUrl.forEach(item => {
            if(currentUrl.indexOf(item) != -1 || targetUrl.indexOf(item) != -1) {
              window.location.href = targetUrl;
            }
          });
        }
      } catch (error) {}

      window.subData = null; // 移除标题（用于一二级导航栏切换处）
      if (typeof $.fancybox != "undefined") {
        $.fancybox.close();    // 关闭弹窗
      }
      volantis.$switcher.removeClass('active'); // 关闭移动端激活的搜索框
      volantis.$header.removeClass('z_search-open'); // 关闭移动端激活的搜索框
      volantis.$wrapper.removeClass('sub'); // 跳转页面时关闭二级导航

      // 解绑事件 避免重复监听
      volantis.$topBtn.unbind('click');
      $('.menu a').unbind('click');
      $(window).unbind('resize');
      $(window).unbind('scroll');
      $(document).unbind('scroll');
      $(document).unbind('click');
      $('body').unbind('click');
	  
    });

    document.addEventListener('pjax:complete', function () {
      // 关于百度统计对 SPA 页面的处理：
      // 方案一：百度统计>管理>单页应用设置中，打开开启按钮即可对SPA进行统计。 https://tongji.baidu.com/web/help/article?id=324
      // 方案二：取消注释下列代码。 https://tongji.baidu.com/web/help/article?id=235
      // 

      // 关于谷歌统计对 SPA 页面的处理：
      // 当应用以动态方式加载内容并更新地址栏中的网址时，也应该更新通过 gtag.js 存储的网页网址。
      // https://developers.google.cn/analytics/devguides/collection/gtagjs/single-page-applications?hl=zh-cn
      

      $('.nav-main').find('.list-v').not('.menu-phone').removeAttr("style",""); // 移除小尾巴的移除
      $('.menu-phone.list-v').removeAttr("style",""); // 移除小尾巴的移除
      $('script[data-pjax], .pjax-reload script').each(function () {
        $(this).parent().append($(this).remove());
      });
      try{
          if (typeof $.fancybox == "undefined") {
            SCload_fancybox();
          } else {
            pjax_fancybox();
          }
        
        
        
        
        
          pjax_initCopyCode();
        
        
        
        
        
      } catch (e) {
        console.log(e);
      }
	  
    });

    document.addEventListener('pjax:error', function (e) {
	  
      window.location.href = e.triggerElement.href;
    });
</script>

    
  </div>
</body>
</html>
